关于au3调用机器码的几点疑问【已解决】
本帖最后由 gto250 于 2013-5-20 21:39 编辑最近又重新学习了一下ward大神的《AutoIt 機械碼的製作與調用》的几个贴子。
然后按图索骥,找了一个C的源码,试着制作了一下,几番摸索,竟然成功了。
因为对C语言,对asm汇编语言都不怎么懂,怎么成功的,基本上就靠运气了,只知其然不知其所以然。
现将代码附上,问题在后面。
C源码int is_vowel(char a)
{
switch(a)
{
case 'a': case 'A':
case 'e': case 'E':
case 'i': case 'I':
case 'o': case 'O':
case 'u': case 'U':
return 1; break;
default:
return 0; break;
}
}
int count_vowel(const char *s)
{
int num;
if(s == '\0')
num = 0;
else
{
if(is_vowel(s))
num = 1 + count_vowel(&s);
else
num = count_vowel(&s);
}
return num;
}这是一段计算一个字母字符串中元音的个数的代码,找的代码有点无聊,不过因为这个简单。
制作成功后的代码:#Include <Memory.au3>
Global $_xxHash_CodeBuffer, $_xxHash_CodeBufferPtr
Global $_xxHash_FastPtr, $_xxHash_StrongPtr
MsgBox(0,"",_xxHash_Strong("abcdefguvo"))
_xxHash_Shutdown()
Func _xxHash_Shutdown()
$_xxHash_CodeBuffer = 0
_MemVirtualFree($_xxHash_CodeBufferPtr, 0, $MEM_RELEASE)
EndFunc
Func _xxHash_Startup()
If Not IsDllStruct($_xxHash_CodeBuffer) Then
Local $Code
$Code = '0xFF01EB04FF02EB195589E58A550883EA4131C080FA3477070FB6D20FBE424F5DC35589E55653518B75084631DB8A46FF84C074140FBEC0890424E8C9FFFFFF83F80183DBFF46EBE589D85A5B5E5DC30100000001000000010000000000010000000000010000000000000000000000010000000100000001000000000001000000000001000000'
Local $Offset_Fast = (StringInStr($Code, "FF01") + 1) / 2
Local $Offset_Strong = (StringInStr($Code, "FF02") + 1) / 2
Local $Opcode = Binary($Code)
$_xxHash_CodeBufferPtr = _MemVirtualAlloc(0, BinaryLen($Opcode), $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
$_xxHash_CodeBuffer = DllStructCreate("byte[" & BinaryLen($Opcode) & "]", $_xxHash_CodeBufferPtr)
DllStructSetData($_xxHash_CodeBuffer, 1, $Opcode)
$_xxHash_StrongPtr = $_xxHash_CodeBufferPtr + $Offset_Strong
Local $TablePtr1 = DllStructCreate("ptr", $_xxHash_CodeBufferPtr + 0x17)
DllStructSetData($TablePtr1, 1, DllStructGetData($TablePtr1, 1) + $_xxHash_CodeBufferPtr)
OnAutoItExitRegister("_xxHash_Shutdown")
EndIf
EndFunc
Func _xxHash_Strong($Data)
If Not IsDllStruct($_xxHash_CodeBuffer) Then _xxHash_Startup()
; $Data = Binary($Data)
Local $Ret = DllCallAddress("uint:cdecl", $_xxHash_StrongPtr, "str",$Data)
Return $Ret
EndFunc
按照ward写的例子修改的,变量都没怎么改动。
asm转换后的代码use32
db 0xFF,0x01
jmp _is_vowel
db 0xFF,0x02
jmp _count_vowel
_is_vowel:
push ebp ; 0000 _ 55
mov ebp, esp ; 0001 _ 89. E5
mov dl, byte ; 0003 _ 8A. 55, 08
sub edx, 65 ; 0006 _ 83. EA, 41
xor eax, eax ; 0009 _ 31. C0
cmp dl, 52 ; 000B _ 80. FA, 34
ja ?_001 ; 000E _ 77, 0A
movzx edx, dl ; 0010 _ 0F B6. D2
movsx eax, byte ; 0013 _ 0F BE. 82, 00000000(d)
?_001:pop ebp ; 001A _ 5D
ret ; 001B _ C3
_count_vowel:; Function begin
push ebp ; 001C _ 55
mov ebp, esp ; 001D _ 89. E5
push esi ; 001F _ 56
push ebx ; 0020 _ 53
push ecx ; 0021 _ 51
mov esi, dword ; 0022 _ 8B. 75, 08
inc esi ; 0025 _ 46
xor ebx, ebx ; 0026 _ 31. DB
?_002:mov al, byte ; 0028 _ 8A. 46, FF
test al, al ; 002B _ 84. C0
jz ?_003 ; 002D _ 74, 14
movsx eax, al ; 002F _ 0F BE. C0
mov dword , eax ; 0032 _ 89. 04 24
call _is_vowel ; 0035 _ E8, FFFFFFC6
cmp eax, 1 ; 003A _ 83. F8, 01
sbb ebx, -1 ; 003D _ 83. DB, FF
inc esi ; 0040 _ 46
jmp ?_002 ; 0041 _ EB, E5
?_003:mov eax, ebx ; 0043 _ 89. D8
pop edx ; 0045 _ 5A
pop ebx ; 0046 _ 5B
pop esi ; 0047 _ 5E
pop ebp ; 0048 _ 5D
ret ; 0049 _ C3
_CSWTCH.1: ; byte
db 01H, 00H, 00H, 00H, 01H, 00H, 00H, 00H ; 0000 _ ........
db 01H, 00H, 00H, 00H, 00H, 00H, 01H, 00H ; 0008 _ ........
db 00H, 00H, 00H, 00H, 01H, 00H, 00H, 00H ; 0010 _ ........
db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H ; 0018 _ ........
db 01H, 00H, 00H, 00H, 01H, 00H, 00H, 00H ; 0020 _ ........
db 01H, 00H, 00H, 00H, 00H, 00H, 01H, 00H ; 0028 _ ........
db 00H, 00H, 00H, 00H, 01H, 00H, 00H, 00H ; 0030 _ ........
存在的问题有以下几个:
1、运行效果不稳定,多次运行后会出现程序崩溃的情况
2、$TablePtr1 = DllStructCreate("ptr", $_xxHash_CodeBufferPtr + 0x17)这一句,虽然用0x17成功了。但是在汇编代码中 movsx eax, byte ; 0013 _ 0F BE. 82, 00000000(d),_CSWTCH.1所在是在0x16,为什么用0x16就不成功?
3、因为对C根本就一窍不通,因此想知道,如果C代码中存在api调用的情况,能否也能按照ward的方法制作成机器码进行调用呢? 需要改动的两处地方:
1、
$bCode = "0xFF01EB04FF02EB1C558BEC8A550883EA4133C080FA34770A0FB6D20FBE82520000005DC3558BEC5653518B75084633DB8A46FF84C074140FBEC0890424E8C6FFFFFF83F80183DBFF46EBE58BC35A5B5E5DC301000000010000000100000000000100000000000100000000000000000000000100000001000000010000000000010000000000010000000000000000000000"
2、
Local $TablePtr1 = DllStructCreate("ptr", $_xxHash_CodeBufferPtr + 0x1E)
DllStructSetData($TablePtr1, 1, DllStructGetData($TablePtr1, 1) + $_xxHash_CodeBufferPtr) 根本看不懂,标记一下 回复 2# pusofalse
为什么和我生成的机器码不一样呢,对asm进行了修改吗?能说明一下吗? 回复 4# gto250
2#的机器码翻译成汇编代码如下。不必在意0x1890000这个起始地址,只看其他指令相对于这个地址的偏移就好了。01890000 FF01 inc dword ptr
01890002 EB 04 jmp short 01890008
01890004 FF02 inc dword ptr
01890006 EB 1C jmp short 01890024
_is_vowel:
01890008 55 push ebp
01890009 8BEC mov ebp, esp
0189000B 8A55 08 mov dl, byte ptr
0189000E 83EA 41 sub edx, 41
01890011 33C0 xor eax, eax
01890013 80FA 34 cmp dl, 34
01890016 77 0A ja short 01890022
01890018 0FB6D2 movzx edx, dl
0189001B 0FBE82 52000000 movsx eax, byte ptr
01890022 5D pop ebp
01890023 C3 retn
_count_vowel:
01890024 55 push ebp
01890025 8BEC mov ebp, esp
01890027 56 push esi
01890028 53 push ebx
01890029 51 push ecx
0189002A 8B75 08 mov esi, dword ptr
0189002D 46 inc esi
0189002E 33DB xor ebx, ebx
01890030 8A46 FF mov al, byte ptr
01890033 84C0 test al, al
01890035 74 14 je short 0189004B
01890037 0FBEC0 movsx eax, al
0189003A 890424 mov dword ptr , eax
0189003D E8 C6FFFFFF call 01890008
01890042 83F8 01 cmp eax, 1
01890045 83DB FF sbb ebx, -1
01890048 46 inc esi
01890049^ EB E5 jmp short 01890030
0189004B 8BC3 mov eax, ebx
0189004D 5A pop edx
0189004E 5B pop ebx
0189004F 5E pop esi
01890050 5D pop ebp
01890051 C3 retn
_CSWTCH.1:
01890052 0100 add dword ptr , eax
01890054 0000 add byte ptr , al
01890056 0100 add dword ptr , eax
01890058 0000 add byte ptr , al
0189005A 0100 add dword ptr , eax
0189005C 0000 add byte ptr , al
0189005E 0000 add byte ptr , al
01890060 0100 add dword ptr , eax
01890062 0000 add byte ptr , al
01890064 0000 add byte ptr , al
01890066 0100 add dword ptr , eax
01890068 0000 add byte ptr , al
0189006A 0000 add byte ptr , al
0189006C 0000 add byte ptr , al
0189006E 0000 add byte ptr , al
01890070 0000 add byte ptr , al
01890072 0100 add dword ptr , eax
01890074 0000 add byte ptr , al
01890076 0100 add dword ptr , eax
01890078 0000 add byte ptr , al
0189007A 0100 add dword ptr , eax
0189007C 0000 add byte ptr , al
0189007E 0000 add byte ptr , al
01890080 0100 add dword ptr , eax
01890082 0000 add byte ptr , al
01890084 0000 add byte ptr , al
01890086 0100 add dword ptr , eax
01890088 0000 add byte ptr , al
0189008A 0000 add byte ptr , al
0189008C 0000 add byte ptr , al
0189008E 0000 add byte ptr , al
回复 5# pusofalse
0FBE82 52000000 movsx 攀愀砀, byte ptr
我对比了一下,代码就在这个位置不一样,为什么你的代码中0FBE82 52000000,52后面的这些0是怎么来的,怎么样修改,才能实现和你一样的机器码? 回复 6# gto250
0FBE82 XXXXXXXX、0FBE42 XX,都是movsx eax, byte ptr 的机器码(?表示偏移),但0FBE82 XXXXXXXX可以寻址到4GB内存空间。0FBE42 XX,由于这里的XX只占一个字节的长度,因此最大内存寻址空间只有256字节。
movsx eax, byte ptr 这一条汇编指令转换为机器码,可以是:
0FBE82 52000000
也可以是:
0FBE42 52
但是,寻址范围超出256字节以后,必须要使用0FBE82 XXXXXXXX形式,例如movsx eax, byte ptr ,这条指令只能转换为0FBE82 00008901。
显然对于movsx eax, byte ptr 这一条指令来说,0FBE42 52相较于0FBE82 52000000,会占用更少的存储空间。你在编译C代码时,编译器会优先选用这种 长度比较短的指令,但是它不知道在编译之后、你还会修改其中的指令。
我在2#给出的机器码是按照你提供的、在OD中一条一条抄写过来的。到movsx eax, byte ptr 这句时,特意使用了0FBE82 XXXXXXXX这种形式,我不知该如何让C编译器也选用这种形式。 回复 7# pusofalse
谢谢P版的回复,我想我已经有点理解了! 太高深了!如何消化得了! 掌握这个派什么用???{:face (382):} 莫名其妙
运行结果 = 4
晕
页:
[1]