一
什么是代码重定位
二
代码重定位的应用场景
CreateRemoteThread
VirtualAllocEx
WriteProcessMemory
将要执行的汇编代码注入到目标进程中。; 2024.11.24 writed by fake77
; kanxue: https://bbs.kanxue.com/homepage-983513.htm
.686
.model flat, stdcall
option casemap:NONE
include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib
WinMain proto :DWORD, :DWORD, :DWORD, :DWORD
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
.data
g_szTargetProcessName db "鎵浄", 0
g_szCaption db "Err", 0
g_szErr1 db "Err 1", 0
g_szErr2 db "Err 2", 0
g_szErr3 db "Err 3", 0
g_szErr4 db "Err 4", 0
g_szErr5 db "Err 5", 0
g_szErr6 db "Err 6", 0
.code
INJECT_BEGIN:
; todo inject code
; inject data area
CODE_BEGIN:
; inject asm code area
CODE_END:
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
; alloc local var
LOCAL hWnd:HWND ; handle of window
LOCAL dwPid:DWORD ; process id for open process
LOCAL hProc:DWORD ; process handle
LOCAL pAddr:LPVOID ; target mem pointer
LOCAL dwWrited:DWORD; writed byte num by WriteProcessMemory
; 1. get window handle
invoke FindWindow, NULL, offset g_szTargetProcessName
mov hWnd, eax
.IF !eax
invoke MessageBox, NULL, offset g_szErr1, offset g_szCaption, MB_OK
.ENDIF
; 2. find process
invoke GetWindowThreadProcessId, hWnd, addr dwPid
.IF !eax
invoke MessageBox, NULL, offset g_szErr2, offset g_szCaption, MB_OK
.ENDIF
; 3. get process handle
invoke OpenProcess, PROCESS_ALL_ACCESS, FALSE, dwPid
mov hProc, eax
.IF !eax
invoke MessageBox, NULL, offset g_szErr3, offset g_szCaption, MB_OK
.ENDIF
; 4. alloc mem in target process and prvg set read write
invoke VirtualAllocEx, hProc, NULL, 1000h, MEM_COMMIT, PAGE_EXECUTE_READWRITE
mov pAddr, eax
.IF !eax
invoke MessageBox, NULL, offset g_szErr4, offset g_szCaption, MB_OK
.ENDIF
; 5. write code to target process
invoke WriteProcessMemory, hProc, pAddr, offset INJECT_BEGIN,
offset CODE_END - offset INJECT_BEGIN, addr dwWrited
.IF !eax
invoke MessageBox, NULL, offset g_szErr5, offset g_szCaption, MB_OK
.ENDIF
; 6. create remote thread to run code
mov eax, pAddr
add eax, offset CODE_BEGIN - offset INJECT_BEGIN ; code entry
invoke CreateRemoteThread, hProc, NULL, 0, eax, NULL, 0, NULL
.IF !eax
invoke MessageBox, NULL, offset g_szErr6, offset g_szCaption, MB_OK
.ENDIF
; makesure stack banlance
ret 10
WinMain endp
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
end start
我们尝试进行注入如下代码,我们希望在目标进程中弹出一个框。
INJECT_BEGIN:
g_szText db "扫雷", 0
g_szCaption db "u got inject", 0
g_pfnMsgBox dd 0
CODE_BEGIN:
invoke MessageBoxA, NULL, offset g_szText, offset g_szCaption, MB_OK
ret 4 ; stdcall 平栈
CODE_END:
MessageBoxA
,整个代码片段都是地址强相关的一切的偏移都是在原有进程的偏移所以在新的进程无法使用。三
段首地址法
INJECT_BEGIN
到CODE_BEGIN
中的各种变量偏移,不能控制的是加载的地址,但是如果我们能够获取到INJECT_BEGIN
的地址则可以根据已知的偏移获取到正确的代码偏移量。LoadLibrary
和GetProcAddress
这两个API是系统自带的PIC API, 他们通常在不同进程中的地址是相同的,我们通过这个API将MessageBoxA
的地址加载到要注入的地址中去。call $ + 5 ; 这里值得注意的是 + 5 是因为call指令的长度是5个字节
; 它的字节码为 E8 00 00 00 00
; 而 $ 符则是在编译器获取当前指令的地址而 + 5是因为
; call 和 jmp一样都是获取的下一条指令的IP当我们call
; $ + 5的时候就可以直接获取到当前 pop eax这条指令的地址
pop eax
.code
INJECT_BEGIN:
g_szText db "扫雷", 0
g_szRemoteCaption db "u got inject", 0
g_pfnMsgBox dd 0 ; MessageBoxA指针
CODE_BEGIN:
call $+5
pop ebx ;获取当前指令地址
sub ebx, (offset CODE_BEGIN - offset INJECT_BEGIN) + 5 ; 获取到段首的偏移
push MB_OK
mov eax, offset g_szText - offset INJECT_BEGIN ; 获取g_szText到段首的偏移
add eax, ebx
push eax
mov eax, offset g_szRemoteCaption - offset INJECT_BEGIN ; 获取g_szRemoteCaption到段首的偏移
add eax, ebx
push ebx
push NULL
mov eax, offset g_pfnMsgBox - offset INJECT_BEGIN
add eax, ebx
call dword ptr [eax] ; 通过指针调用
; invoke MessageBoxA, NULL, offset g_szText, offset g_szRemoteCaption, MB_OK
ret 4 ; stdcall 平栈CODE_END:
CODE_END:
; WinMain....
; 因为是代码段所以要更改下权限
invoke VirtualProtect,offset INJECT_BEGIN, 1000h, PAGE_EXECUTE_READWRITE, addr dwOld
; check ...
; 获取user32的地址
invoke LoadLibrary, offset g_user32
; check ...
mov hUser32, eax
; 获取到MessageBoxA的地址
invoke GetProcAddress, hUser32, g_message
; check ...
mov g_pfnMsgBox, eax
; 还原权限
invoke VirtualProtect,offset INJECT_BEGIN, 1000h, dwOld, addr dwOld
; check ...
; WinMain....
四
段偏移法
原进程地址 + 偏移 = 目标进程的地址
的方式重定位代码段。.code
INJECT_BEGIN:
g_szText db "扫雷", 0
g_szRemoteCaption db "u got inject", 0
g_pfnMsgBox dd 0 ; MessageBoxA指针
CODE_BEGIN:
call $+5
NEXT:
pop ebx ;获取当前指令地址
; sub ebx, (offset CODE_BEGIN - offset INJECT_BEGIN) + 5 ; 获取到段首的偏移
sub ebx, offset NEXT ; NEXT是在编译其确定的地址而ebx则是运行时确定的其差值就是偏移值.
push MB_OK
;mov eax, offset g_szRemoteCaption - offset INJECT_BEGIN ; 获取g_szRemoteCaption到段首的偏移
mov eax, offset g_szText
add eax, ebx
push eax
;mov eax, offset g_szText - offset INJECT_BEGIN ; 获取g_szText到段首的偏移
mov eax, offset g_szRemoteCaption
add eax, ebx
push eax
push NULL
; mov eax, offset g_pfnMsgBox - offset INJECT_BEGIN
mov eax, offset g_pfnMsgBox
add eax, ebx
call dword ptr [eax] ; 通过指针调用
; invoke MessageBoxA, NULL, offset g_szText, offset g_szRemoteCaption, MB_OK
ret 4 ; stdcall 平栈CODE_END:
CODE_END:
看雪ID:TeddyBe4r
https://bbs.kanxue.com/user-home-983513.htm
#
原文始发于微信公众号(看雪学苑):浅析代码重定位技术
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论