MASM32 x86 windows 程序集 GetCommandLineToArgvW
MASM32 x86 windows assembly GetCommandLineToArgvW
请问如何在x86汇编中使用CommandLineToArgvW函数。我遇到了麻烦。截至今天,我所能打印的只是参数的数量以及 cmd 中的程序执行。我想将参数保存在不同的变量中。我该怎么做?
我的代码如下所示:
include \masm32\include\masm32rt.inc
.data
Format db "%d", 10, 0
.data?
Arguments db 100 dup(?)
.code
start:
mov esi, offset Arguments
push ebp
mov ebp, esp
sub esp, 4
call GetCommandLineW
lea ecx, dword ptr[ebp - 4]
push ecx
push eax
call CommandLineToArgvW
mov esi, eax
push offset Arguments
call StdOut
push dword ptr [ebp - 4]
push offset Format
call crt_printf
add esp, 8
push 0
call ExitProcess
end start
我现在的输出是参数的数量。例如:
- D:\masm32>Hello.exe我是你好
- 4
- D:\masm32>
CommandLineToArgvW
至少要注意三个怪癖:
结果是指向 宽 字符串的指针数组。
MASM32 函数 crt_printf
使用 Microsoft VC 运行时库 (msvcrt.dll) 中的函数 printf
。因此,您可以使用大写 'S' 作为类型字段字符。看看printf
Type Field Characters on MSDN.
结果是指向字符串的指针数组的第一个元素的地址。
大多数打印函数需要一个指向字符串的指针,而不是指向字符串指针的指针。您必须取消引用该地址才能获得指向该字符串的指针。命令行 "Hello.exe I am Hello" 将被拆分为四个字符串:"Hello.exe"、"I"、"am"、"Hello"。指向这些字符串的指针是在一个有4个指针的数组中找到的:[指向"Hello.exe"的指针]、[指向"I"的指针],依此类推。假设函数 CommandLineToArgvW
有一个 return 值 EAX=0x001445A8。 Hexdump 看起来像
Address Hex dump ASCII
001445A8 B8 45 14 00|CC 45 14 00|D0 45 14 00|D6 45 14 00| ¸E.ÌE.ÐE.ÖE.
001445B8 48 00 65 00|6C 00 6C 00|6F 00 2E 00|65 00 78 00| H.e.l.l.o...e.x.
001445C8 65 00 00 00|49 00 00 00|61 00 6D 00|00 00 48 00| e...I...a.m...H.
001445D8 65 00 6C 00|6C 00 6F 00|00 00 00 00|00 00 00 00| e.l.l.o.........
地址 0x001445A8 是指向 0x001445B8 的指针(以小端格式显示在转储中),这是宽字符格式的 "Hello.exe" 的开头。下一个指针在 0x001445A8 后面 4 个字节:0x001445CC - 指向 "I"。下一个指针距离 4 个字节,依此类推。您可以通过添加 4 快速遍历该数组。您可以通过将索引乘以 4 轻松获得列表中间字符串的地址 - 指向第三个字符串的指针("am",索引: 2) 位于 0x001445A8 + 2 * 4 = 0x001445B0 => 0x001445D0 => "am".
函数分配内存,必须用LocalFree
手动释放。
我尽量少改动你的程序:
include \masm32\include\masm32rt.inc
.data
Format db "argc: %d", 10, 0
fmt db "%S",10,0 ; %S: printf wide-character string / wprintf single-character string
szArglist dd ?
.code
start:
push ebp
mov ebp, esp
sub esp, 4
; https://msdn.microsoft.com/library/windows/desktop/ms683156.aspx
call GetCommandLineW ; EAX = pointer to the command line
; https://msdn.microsoft.com/library/windows/desktop/bb776391.aspx
lea ecx, dword ptr[ebp - 4] ; Get the current address of [ebp-4]
push ecx ; int *pNumArgs (Pointer to a SDWORD, here at ebp-4)
push eax ; LPCWSTR lpCmdLine (from GetCommandLineW)
call CommandLineToArgvW
mov [szArglist], eax ; Store the result of CommandLineToArgvW (at least for LocalFree)
mov esi, eax ; ESI = address of a pointer (the first element in szArglist)
mov ebx, [ebp-4] ; Countdown the number of arguments
@@: ; Loop
push dword ptr [esi] ; Pointer to a string (dereferenced esi)
push OFFSET fmt ; Format string
call crt_printf ; printf (""%S\n", esi)
add esp, 8 ; Clear the stack after printf
add esi, 4 ; Next address of a pointer (next element of szArglist)
dec ebx ; Countdown the number of arguments
jne @B ; Loop to the last @@
push dword ptr [szArglist]
call LocalFree ; Free the memory occupied by CommandLineToArgvW
push dword ptr [ebp - 4] ; Value that is stored in [ebp-4]
push offset Format ; Pointer to format string
call crt_printf ; printf ("argc: %d\n", [ebp-4])
add esp, 8 ; Clear the stack after printf
push 0
call ExitProcess
end start
MASM32 函数StdOut
无法处理宽字符串。您必须先将它们转换为 ANSI 字符串。用于该目的的 Windows 函数是 WideCharToMultiByte
:
include \masm32\include\masm32rt.inc
.data
szArglist dd ?
buf db 1024 DUP (?)
crlf db 13, 10, 0 ; New line
.code
start:
push ebp
mov ebp, esp
sub esp, 4
; https://msdn.microsoft.com/library/windows/desktop/ms683156.aspx
call GetCommandLineW ; EAX = pointer to the command line
; https://msdn.microsoft.com/library/windows/desktop/bb776391.aspx
lea ecx, dword ptr[ebp - 4] ; Get the current address of [ebp-4]
push ecx ; int *pNumArgs (Pointer to a SDWORD, here at ebp-4)
push eax ; LPCWSTR lpCmdLine (from GetCommandLineW)
call CommandLineToArgvW
mov [szArglist], eax ; Store the result of CommandLineToArgvW (at least for LocalFree)
mov esi, eax ; ESI = address of a pointer (the first element in szArglist)
mov ebx, [ebp-4] ; Countdown the number of arguments
@@: ; Loop
; https://msdn.microsoft.com/library/windows/desktop/dd374130.aspx
push NULL ; LPBOOL lpUsedDefaultChar
push NULL ; LPCSTR lpDefaultChar
push SIZEOF buf ; int cbMultiByte
push OFFSET buf ; LPSTR lpMultiByteStr
push -1 ; int cchWideChar
push [esi] ; LPCWSTR lpWideCharStr (dereferenced esi)
push 0 ; DWORD dwFlags
push 0 ; UINT CodePage
call WideCharToMultiByte
push OFFSET buf ; Pointer to an ANSI string
call StdOut
push OFFSET crlf ; New line
call StdOut
add esi, 4 ; Next address of a pointer (next element of szArglist)
dec ebx ; Countdown the number of arguments
jne @B ; Loop to the last @@
push dword ptr [szArglist]
call LocalFree ; Free the memory occupied by CommandLineToArgvW
push OFFSET buf
push dword ptr [ebp - 4]
call dwtoa
push OFFSET buf ; Pointer to a string
call StdOut ; printf (""%S\n", esi)
push OFFSET crlf
call StdOut
push 0
call ExitProcess
end start
请问如何在x86汇编中使用CommandLineToArgvW函数。我遇到了麻烦。截至今天,我所能打印的只是参数的数量以及 cmd 中的程序执行。我想将参数保存在不同的变量中。我该怎么做?
我的代码如下所示:
include \masm32\include\masm32rt.inc
.data
Format db "%d", 10, 0
.data?
Arguments db 100 dup(?)
.code
start:
mov esi, offset Arguments
push ebp
mov ebp, esp
sub esp, 4
call GetCommandLineW
lea ecx, dword ptr[ebp - 4]
push ecx
push eax
call CommandLineToArgvW
mov esi, eax
push offset Arguments
call StdOut
push dword ptr [ebp - 4]
push offset Format
call crt_printf
add esp, 8
push 0
call ExitProcess
end start
我现在的输出是参数的数量。例如:
- D:\masm32>Hello.exe我是你好
- 4
- D:\masm32>
CommandLineToArgvW
至少要注意三个怪癖:
结果是指向 宽 字符串的指针数组。
MASM32 函数
crt_printf
使用 Microsoft VC 运行时库 (msvcrt.dll) 中的函数printf
。因此,您可以使用大写 'S' 作为类型字段字符。看看printf
Type Field Characters on MSDN.结果是指向字符串的指针数组的第一个元素的地址。
大多数打印函数需要一个指向字符串的指针,而不是指向字符串指针的指针。您必须取消引用该地址才能获得指向该字符串的指针。命令行 "Hello.exe I am Hello" 将被拆分为四个字符串:"Hello.exe"、"I"、"am"、"Hello"。指向这些字符串的指针是在一个有4个指针的数组中找到的:[指向"Hello.exe"的指针]、[指向"I"的指针],依此类推。假设函数
CommandLineToArgvW
有一个 return 值 EAX=0x001445A8。 Hexdump 看起来像Address Hex dump ASCII 001445A8 B8 45 14 00|CC 45 14 00|D0 45 14 00|D6 45 14 00| ¸E.ÌE.ÐE.ÖE. 001445B8 48 00 65 00|6C 00 6C 00|6F 00 2E 00|65 00 78 00| H.e.l.l.o...e.x. 001445C8 65 00 00 00|49 00 00 00|61 00 6D 00|00 00 48 00| e...I...a.m...H. 001445D8 65 00 6C 00|6C 00 6F 00|00 00 00 00|00 00 00 00| e.l.l.o.........
地址 0x001445A8 是指向 0x001445B8 的指针(以小端格式显示在转储中),这是宽字符格式的 "Hello.exe" 的开头。下一个指针在 0x001445A8 后面 4 个字节:0x001445CC - 指向 "I"。下一个指针距离 4 个字节,依此类推。您可以通过添加 4 快速遍历该数组。您可以通过将索引乘以 4 轻松获得列表中间字符串的地址 - 指向第三个字符串的指针("am",索引: 2) 位于 0x001445A8 + 2 * 4 = 0x001445B0 => 0x001445D0 => "am".
函数分配内存,必须用
LocalFree
手动释放。
我尽量少改动你的程序:
include \masm32\include\masm32rt.inc
.data
Format db "argc: %d", 10, 0
fmt db "%S",10,0 ; %S: printf wide-character string / wprintf single-character string
szArglist dd ?
.code
start:
push ebp
mov ebp, esp
sub esp, 4
; https://msdn.microsoft.com/library/windows/desktop/ms683156.aspx
call GetCommandLineW ; EAX = pointer to the command line
; https://msdn.microsoft.com/library/windows/desktop/bb776391.aspx
lea ecx, dword ptr[ebp - 4] ; Get the current address of [ebp-4]
push ecx ; int *pNumArgs (Pointer to a SDWORD, here at ebp-4)
push eax ; LPCWSTR lpCmdLine (from GetCommandLineW)
call CommandLineToArgvW
mov [szArglist], eax ; Store the result of CommandLineToArgvW (at least for LocalFree)
mov esi, eax ; ESI = address of a pointer (the first element in szArglist)
mov ebx, [ebp-4] ; Countdown the number of arguments
@@: ; Loop
push dword ptr [esi] ; Pointer to a string (dereferenced esi)
push OFFSET fmt ; Format string
call crt_printf ; printf (""%S\n", esi)
add esp, 8 ; Clear the stack after printf
add esi, 4 ; Next address of a pointer (next element of szArglist)
dec ebx ; Countdown the number of arguments
jne @B ; Loop to the last @@
push dword ptr [szArglist]
call LocalFree ; Free the memory occupied by CommandLineToArgvW
push dword ptr [ebp - 4] ; Value that is stored in [ebp-4]
push offset Format ; Pointer to format string
call crt_printf ; printf ("argc: %d\n", [ebp-4])
add esp, 8 ; Clear the stack after printf
push 0
call ExitProcess
end start
MASM32 函数StdOut
无法处理宽字符串。您必须先将它们转换为 ANSI 字符串。用于该目的的 Windows 函数是 WideCharToMultiByte
:
include \masm32\include\masm32rt.inc
.data
szArglist dd ?
buf db 1024 DUP (?)
crlf db 13, 10, 0 ; New line
.code
start:
push ebp
mov ebp, esp
sub esp, 4
; https://msdn.microsoft.com/library/windows/desktop/ms683156.aspx
call GetCommandLineW ; EAX = pointer to the command line
; https://msdn.microsoft.com/library/windows/desktop/bb776391.aspx
lea ecx, dword ptr[ebp - 4] ; Get the current address of [ebp-4]
push ecx ; int *pNumArgs (Pointer to a SDWORD, here at ebp-4)
push eax ; LPCWSTR lpCmdLine (from GetCommandLineW)
call CommandLineToArgvW
mov [szArglist], eax ; Store the result of CommandLineToArgvW (at least for LocalFree)
mov esi, eax ; ESI = address of a pointer (the first element in szArglist)
mov ebx, [ebp-4] ; Countdown the number of arguments
@@: ; Loop
; https://msdn.microsoft.com/library/windows/desktop/dd374130.aspx
push NULL ; LPBOOL lpUsedDefaultChar
push NULL ; LPCSTR lpDefaultChar
push SIZEOF buf ; int cbMultiByte
push OFFSET buf ; LPSTR lpMultiByteStr
push -1 ; int cchWideChar
push [esi] ; LPCWSTR lpWideCharStr (dereferenced esi)
push 0 ; DWORD dwFlags
push 0 ; UINT CodePage
call WideCharToMultiByte
push OFFSET buf ; Pointer to an ANSI string
call StdOut
push OFFSET crlf ; New line
call StdOut
add esi, 4 ; Next address of a pointer (next element of szArglist)
dec ebx ; Countdown the number of arguments
jne @B ; Loop to the last @@
push dword ptr [szArglist]
call LocalFree ; Free the memory occupied by CommandLineToArgvW
push OFFSET buf
push dword ptr [ebp - 4]
call dwtoa
push OFFSET buf ; Pointer to a string
call StdOut ; printf (""%S\n", esi)
push OFFSET crlf
call StdOut
push 0
call ExitProcess
end start