gto250 发表于 2013-5-18 20:29:37

关于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的方法制作成机器码进行调用呢?

pusofalse 发表于 2013-5-19 00:19:51

需要改动的两处地方:
1、
$bCode = "0xFF01EB04FF02EB1C558BEC8A550883EA4133C080FA34770A0FB6D20FBE82520000005DC3558BEC5653518B75084633DB8A46FF84C074140FBEC0890424E8C6FFFFFF83F80183DBFF46EBE58BC35A5B5E5DC301000000010000000100000000000100000000000100000000000000000000000100000001000000010000000000010000000000010000000000000000000000"

2、
Local $TablePtr1 = DllStructCreate("ptr", $_xxHash_CodeBufferPtr + 0x1E)
DllStructSetData($TablePtr1, 1, DllStructGetData($TablePtr1, 1) + $_xxHash_CodeBufferPtr)

haijie1223 发表于 2013-5-19 07:50:40

根本看不懂,标记一下

gto250 发表于 2013-5-19 20:41:27

回复 2# pusofalse


    为什么和我生成的机器码不一样呢,对asm进行了修改吗?能说明一下吗?

pusofalse 发表于 2013-5-20 06:58:28

回复 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

gto250 发表于 2013-5-20 20:05:45

回复 5# pusofalse


    0FBE82 52000000 movsx 攀愀砀, byte ptr

我对比了一下,代码就在这个位置不一样,为什么你的代码中0FBE82 52000000,52后面的这些0是怎么来的,怎么样修改,才能实现和你一样的机器码?

pusofalse 发表于 2013-5-20 20:54:51

回复 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编译器也选用这种形式。

gto250 发表于 2013-5-20 21:38:53

回复 7# pusofalse


    谢谢P版的回复,我想我已经有点理解了!

penguinl 发表于 2013-5-24 00:22:45

太高深了!如何消化得了!

tts780679 发表于 2013-5-24 18:02:46

掌握这个派什么用???{:face (382):}

ba3ba4 发表于 2013-6-5 19:01:06

莫名其妙

运行结果 = 4

页: [1]
查看完整版本: 关于au3调用机器码的几点疑问【已解决】