小俊 发表于 2017-12-12 20:18

【汇编】通过汇编获得GetProcAddress函数地址

本帖最后由 wushaominkk 于 2018-8-2 14:39 编辑

.386
.model flat,stdcall
option casemap:none

.code
main:
      push ebp
      mov ebp,esp
      sub esp,10h
      ;------------------------------------------------------
      ;mov ebx,fs:   ;进入OEP的时候,ebx默认是PEB
      mov ebx,
      mov ebx,
      mov ebx,
      mov ebx,
      mov ebx,    ;Ebx = kernel32.dll模块基址
      mov eax,    ;Eax = NtHeader offset
      add eax,ebx          ;NtHeader offset=>VA
      mov eax,    ;Eax = 导出表RVA
      add eax,ebx          ;导出表RVA=>VA
      mov edx,    ;Edx = 名称表RVA
      add edx,ebx          ;名称表RVA=>VA
      xor ecx,ecx          ;Ecx清零
MyLoop:
      mov esi,;Esi = 函数名RVA
      add esi,ebx          ;函数名RVA=>VA
      inc ecx            ;Ecx++
      ;03   7
      ;GetProcAddress
      movzx edi,byte ptr   ;取函数名第0个字节
      cmp edi,'G';如果等于ZF会被置为1
      jnz MyLoop   ;ZF为0则跳转
      movzx edi,byte ptr ;取函数名第3个字节
      cmp edi,'P'
      jnz MyLoop
      movzx edi,byte ptr ;取函数名第7个字节
      cmp edi,'A'
      jnz MyLoop
      ;到了这,说明已经找到了GetProcAddress在名称表中的位置了
      ;注意:Ecx现在等于真正的下标+1,而不是真正的下标
      dec ecx ;Ecx减一,才是真正的下标
      mov edx,   ;Edx = 序号表RVA
      add edx,ebx         ;序号表RVA=>VA
      movzx ecx,word ptr ;通过序号表找到地址表下标
      mov edx,   ;Edx = 地址表RVA
      add edx,ebx         ;地址表RVA=>VA
      mov esi, ;函数RVA
      add esi,ebx         ;函数RVA=>VA
      mov ,ebx;保存kernel32.dll模块基址
      mov ,esi;保存GetProcAddress函数地址
      call PushStr1    ;将下面的数据入栈
      db "LoadLibraryA",0   ;参数2
PushStr1:
      push           ;参数1
      call dword ptr ;GetProcAddress
      mov ,eax   ;保存LoadLibraryA函数地址
      call PushStr2         ;将下面的数据入栈
      db "user32.dll",0   ;参数1
PushStr2:
      call eax ;LoadLibraryA
      mov ,eax   ;保存user32.dll模块基址
      ;------------------------------------------------------
      add esp,10h
      pop ebp
      ret
end main

版本2
.386
.model flat,stdcall
option casemap:none
assume fs:nothing

;[+0]   本模块实例句柄
;[+4]   kernel32.dll   模块基址
;[+8]   GetProcAddress 函数地址
;[+0Ch] LoadLibraryA   函数地址
;[+10h] user32.dll   模块基址

.code
main:
      push ebp
      mov ebp,esp
      call GetGlobal
      mov edi,eax
      ;----------------------------------------------
      ;mov ebx,fs:
      mov ebx,
      mov ebx,
      mov edx,
      mov ,edx   ;[+0]保存本模块实例句柄
      mov ebx,
      mov ebx,
      mov ebx,
      mov ,ebx   ;[+4]保存kernel32.dll模块基址
      mov eax, ;取Nt头文件偏移
      add eax,ebx       ;offset=>VA
      mov eax, ;取导出表RVA
      add eax,ebx       ;RVA=>VA
      mov edx, ;取名称表RVA
      add edx,ebx       ;RVA=>VA
      xor ecx,ecx       ;ecx清零
      MyLoop:
      mov esi,   ;取函数名RVA
      add esi,ebx         ;RVA=>VA
      inc ecx               ;ecx++
      cmp byte ptr,'G' ;如果等于ZF会被置为1
      jnz MyLoop            ;ZF为0则跳转
      cmp byte ptr,'P'
      jnz MyLoop
      cmp byte ptr,'A'
      jnz MyLoop
      dec ecx             ;ecx-- 真正的下标
      mov edx,   ;取序号表RVA
      add edx,ebx         ;RVA=>VA
      mov cx,;通过序号表找到地址表下标
      mov edx,   ;取地址表RVA
      add edx,ebx         ;RVA=>VA
      mov esi, ;取函数RVA
      add esi,ebx         ;RVA=>VA
      mov ,esi   ;保存GetProcAddress函数地址
      call PushStr1       ;将下面的数据地址入栈
      db "LoadLibraryA",0 ;参数2:要获取的函数名
      PushStr1:
      push ebx            ;参数1:kernel32.dll模块基址
      call esi            ;GetProcAddress
      mov ,eax   ;保存LoadLibraryA函数地址
      call PushStr2       ;将下面的数据地址入栈
      db "user32.dll",0   ;参数1:需要Load的DLL名称
      PushStr2:
      call eax            ;LoadLibraryA
      mov ,eax   ;保存user32.dll模块基址
      ;----------------------------------------------
      pop ebp
      ret
GetGlobal:
      mov eax,
      and eax,0FFFFF000h
      add eax,200h
      ret
end main

加强版:
.386
.model flat,stdcall
option casemap:none
assume fs:nothing

;[+0]   本模块实例句柄
;[+4]   kernel32.dll      模块基址
;[+8]   GetProcAddress    函数地址
;[+0Ch] LoadLibraryA      函数地址
;[+10h] user32.dll      模块基址
;[+14h] ClassName
;[+18h]~[+3Ch] WNDCLASSA结构体
;[+40h] RegisterClassA    函数地址
;[+44h] DefWindowProcA    函数地址
;[+48h] CreateWindowExA   函数地址
;[+4Ch] GetMessageA       函数地址
;[+50h] DispatchMessageA函数地址
;[+54h]~[+60h] MSG      结构体
;[+64h] 窗口句柄

.code
main:
      push ebp
      mov ebp,esp
      call GetGlobal
      mov edi,eax
      ;----------------------------------------------------
      ;mov ebx,fs:
      mov ebx,
      mov ebx,
      mov edx,
      mov ,edx   ;[+0]保存本模块实例句柄
      mov ebx,
      mov ebx,
      mov ebx,
      mov ,ebx   ;[+4]保存kernel32.dll模块基址
      mov eax, ;取Nt头文件偏移
      add eax,ebx       ;offset=>VA
      mov eax, ;取导出表RVA
      add eax,ebx       ;RVA=>VA
      mov edx, ;取名称表RVA
      add edx,ebx       ;RVA=>VA
      xor ecx,ecx       ;ecx清零
      MyLoop:
      mov esi,   ;取函数名RVA
      add esi,ebx         ;RVA=>VA
      inc ecx               ;ecx++
      cmp byte ptr,'G' ;如果等于ZF会被置为1
      jnz MyLoop            ;ZF为0则跳转
      cmp byte ptr,'P'
      jnz MyLoop
      cmp byte ptr,'A'
      jnz MyLoop
      dec ecx             ;ecx-- 真正的下标
      mov edx,   ;取序号表RVA
      add edx,ebx         ;RVA=>VA
      mov cx,;通过序号表找到地址表下标
      mov edx,   ;取地址表RVA
      add edx,ebx         ;RVA=>VA
      mov esi, ;取函数RVA
      add esi,ebx         ;RVA=>VA
      mov ,esi   ;保存GetProcAddress函数地址
      call PushStr1       ;将下面的数据地址入栈
      db "LoadLibraryA",0 ;参数2:要获取的函数名
      PushStr1:
      push ebx            ;参数1:kernel32.dll模块基址
      call esi            ;GetProcAddress
      mov ,eax   ;保存LoadLibraryA函数地址
      call PushStr2       ;将下面的数据地址入栈
      db "user32.dll",0   ;参数1:需要Load的DLL名称
      PushStr2:
      call eax            ;LoadLibraryA
      mov ,eax   ;保存user32.dll模块基址
      
      mov dword ptr,434241h ;ClassName "ABC"
      
      mov dword ptr,0       ;style
      mov dword ptr,WndProc ;lpfnWndProc
      mov dword ptr,0       ;cbClsExtra
      mov dword ptr,0       ;cbWndExtra
      mov edx,                  ;取实例句柄
      mov dword ptr,edx   ;hInstance
      mov dword ptr,0       ;hIcon
      mov dword ptr,0       ;hCursor
      mov dword ptr,0       ;hbrBackground
      mov dword ptr,0       ;lpszMenuName
      lea edx,            ;取字符串地址
      mov dword ptr,edx   ;lpszClassName
      
      call PushStr3         ;将下面的数据地址入栈
      db "RegisterClassA",0 ;参数2:要获取的函数名
      PushStr3:
      push       ;参数1:user32.dll模块基址
      call esi            ;GetProcAddress
      mov ,eax   ;保存RegisterClassA函数地址
      lea edx,   ;取WNDCLASSA结构体地址
      push edx            ;参数1:&WNDCLASSA
      call eax            ;RegisterClassA
      
      call PushStr4         ;将下面的数据地址入栈
      db "DefWindowProcA",0 ;参数2:要获取的函数名
      PushStr4:
      push       ;参数1:user32.dll模块基址
      call esi            ;GetProcAddress
      mov ,eax   ;保存DefWindowProcA函数地址
      
      call PushStr5          ;将下面的数据地址入栈
      db "CreateWindowExA",0 ;参数2:要获取的函数名
      PushStr5:
      push          ;参数1:user32.dll模块基址
      call esi               ;GetProcAddress
      mov ,eax      ;保存CreateWindowExA函数地址
      
      push 0               ;lpParam
      push              ;hInstance
      push 0               ;hMenu
      push 0               ;hWndParent
      push 200               ;nHeight
      push 400               ;nWidth
      push 0               ;Y
      push 0               ;X
      push 10080000h         ;dwStyle
      push 0               ;lpWindowName
      lea edx,      ;取字符串地址
      push edx               ;lpClassName
      push 00000010h         ;dwExStyle
      call eax               ;CreateWindowExA
      mov ,eax      ;保存窗口句柄
      
      call CreateControl   ;创建控件
      
      call PushStr6         ;将下面的数据地址入栈
      db "GetMessageA",0      ;参数2:要获取的函数名
      PushStr6:
      push           ;参数1:user32.dll模块基址
      call esi                ;GetProcAddress
      mov ,eax       ;保存GetMessageA函数地址
      
      call PushStr7         ;将下面的数据地址入栈
      db "DispatchMessageA",0 ;参数2:要获取的函数名
      PushStr7:
      push           ;参数1:user32.dll模块基址
      call esi                ;GetProcAddress
      mov ,eax       ;保存DispatchMessageA函数地址
      
      MsgLoop:
      call GetGlobal
      mov edi,eax
      push 0
      push 0
      push 0
      lea edx,
      push edx
      call dword ptr
      lea edx,
      push edx
      call dword ptr
      jmp      MsgLoop
      ;----------------------------------------------------
      pop ebp
      ret
WndProc:
      push ebp
      mov ebp,esp
      call GetGlobal
      mov edi,eax
      ;------------------------------------------
      push
      push
      push
      push
      call dword ptr
      ;------------------------------------------
      pop ebp
      ret 10h
CreateControl:
      call GetGlobal
      mov edi,eax
      push 0               ;lpParam
      push              ;hInstance
      push 1               ;hMenu
      push          ;hWndParent
      push 20                ;nHeight
      push 100               ;nWidth
      push 0               ;Y
      push 0               ;X
      push 50800000h         ;dwStyle
      push 0               ;lpWindowName
      call PushStr10
      db "Edit",0          ;lpClassName
      PushStr10:
      push 0               ;dwExStyle
      call dword ptr ;CreateWindowExA
      ret
GetGlobal:
      mov eax,
      and eax,0FFFFF000h
      add eax,400h
      ret
end main

小俊 发表于 2017-12-12 20:42

ShellCode
8B 5B 0C 8B 5B 0C 8B 1B 8B 1B 8B 5B 18 8B 43 3C
03 C3 8B 40 78 03 C3 8B 50 20 03 D3 33 C9 8B 34
8A 03 F3 41 0F B6 3E 83 FF 47 75 F2 0F B6 7E 03
83 FF 50 75 E9 0F B6 7E 07 83 FF 41 75 E0 49 8B
50 24 03 D3 0F B7 0C 4A 8B 50 1C 03 D3 8B 34 8A
03 F3 8B FB C3

XC_蛋蛋君 发表于 2017-12-12 20:46

老铁给力哇{:301_997:}

hbe 发表于 2017-12-12 20:57

好好学习下

qaz003 发表于 2017-12-12 21:35

谢谢分享。。注释得很祥细。。。

寒尘丶Coldust 发表于 2017-12-12 23:34

很详细 不过具体用的话 还是得像shellcode那样比较精简

chen4321 发表于 2017-12-13 08:19

说的很明白,谢谢分享

XT0624 发表于 2017-12-13 09:26

厉害阿 老哥

565266718 发表于 2018-2-6 09:01

支持。。。。。

Adrian_07 发表于 2018-8-2 14:24

谢谢分享!!
页: [1]
查看完整版本: 【汇编】通过汇编获得GetProcAddress函数地址