1. 什么是重定位

本来每个进程都各自的进程地址空间, 但如果使用了比如注入技术后, 自身的那段代码就会进入到别人的进程地址空间内, 这将导致内部使用的API地址和变量地址发生变化, 因为注入到的位置和自身在自己进程地址空间种的基址很可能会不一样。

2. 如何解决重定位问题

使用汇编语言可以很好的解决重定位问题, 下面来看这段代码:

call $+5   ;机器码实际上是 E8 xx xx xx xx,一共5个字节
           ;$是但当前指令所在的地址,$+5就是越过当前指令
           ;获取下一条指令也就是pop ebx的地址并压入堆栈
pop ebx   ;把pop ebx指令所在的地址[由call压入]弹出到ebx中

还有一段等价代码

call NEXT
NEXT:
pop ebx

上面两端代码的含义是一样的, 都是为了获取当前进程空间种当前指令的动态地址
代码重定位技术-LMLPHP

3. 实例

下面这个实例使用了远线程注入方式, 把一段重定位过的汇编代码注入到了目标进程

.386
.model flat, stdcall  ;32 bit memory model
option casemap :none  ;case sensitive

include windows.inc
include kernel32.inc
include user32.inc
include Comctl32.inc
include shell32.inc

includelib kernel32.lib
includelib user32.lib
includelib Comctl32.lib
includelib shell32.lib

DlgProc			PROTO	:HWND,:UINT,:WPARAM,:LPARAM

.const

IDD_DIALOG			equ 101
IDC_EDT_BROWSE		equ 1001
IDC_BTN_BROWSE		equ 1002
IDC_BTN_INJECT		equ 1003
IDC_STATIC_STATUS		equ 1004
IDC_EDT_PID			 equ 1005
IDC_STATIC_PID		equ 1006

.data?
hInstance			dd ?

.data 
g_strProcessName db MAX_PATH dup(0)
g_ddShellcodeSize dd offset INJECT_CODE_END - offset INJECT_CODE

g_szUser32 db "user32.dll", 0
g_szMsgBox db "MessageBoxA", 0

g_szOk db "状态: 成功", 0
g_szFail db "状态: 失败", 0
.code

start:
	invoke GetModuleHandle,NULL
	mov	hInstance,eax

    	invoke InitCommonControls
	invoke DialogBoxParam,hInstance,IDD_DIALOG,NULL,addr DlgProc,NULL
	invoke ExitProcess,0

; ofst = new - origin
; NewMsgBox = OldMsgBox + ofst
INJECT_CODE:
	jmp STARTINJ

	g_szMsgData db "你快乐了吗?", 0
	g_szMsgCaption db "哈哈", 0
	g_pfnMessageBoxA dd 0
STARTINJ:
	; 进行重定位, 获取偏移
	call NEXT 
NEXT:
	pop ebx 
	sub ebx, offset NEXT
	
	push MB_OK
	; 对MessageBoxA的标题进行重定位
	mov eax, offset g_szMsgCaption
	add eax, ebx
	push eax
	; 对MessageBoxA的内容进行重定位
	mov eax, offset g_szMsgData
	add eax, ebx
	push eax
	
	push NULL
	; 对MessageBoxA进行重定位
	mov eax, offset g_pfnMessageBoxA
	add eax, ebx
	call dword ptr [eax]
	ret

INJECT_CODE_END:


GetPidByProcessName PROC stdcall hWnd:HWND
	LOCAL @hSnapshot:HANDLE 
	LOCAL @stPe:PROCESSENTRY32 
	LOCAL @dwPid:DWORD

	; 初始化局部变量
	mov @dwPid, 0
	mov @hSnapshot, INVALID_HANDLE_VALUE
	; 获取目标进程名
	invoke GetDlgItemText, hWnd, IDC_EDT_PID, offset g_strProcessName, size g_strProcessName
	; 创建快照句柄
	invoke CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS, 0
	mov @hSnapshot, eax 
	cmp eax, INVALID_HANDLE_VALUE
	je CLEARSTUFF
	; 遍历进程
	mov @stPe.dwSize, size PROCESSENTRY32
	invoke Process32First, @hSnapshot, addr @stPe
	test eax, eax
	jz CLEARSTUFF
GETPIDLOOP:
	invoke lstrcmp, addr @stPe.szExeFile, addr g_strProcessName
	jz GETPIDOKAY
	invoke RtlZeroMemory, addr @stPe, size PROCESSENTRY32
	mov @stPe.dwSize, size PROCESSENTRY32
	invoke Process32Next, @hSnapshot, addr @stPe 
	test eax, eax 
	jnz GETPIDLOOP
	jmp CLEARSTUFF
GETPIDOKAY:
	mov eax, @stPe.th32ProcessID
	mov @dwPid, eax
CLEARSTUFF:
	cmp @hSnapshot, INVALID_HANDLE_VALUE
	jz ENDING
	invoke CloseHandle, @hSnapshot 
	mov @hSnapshot, INVALID_HANDLE_VALUE
ENDING:
	mov eax, @dwPid
	ret

GetPidByProcessName endp

InjectObject PROC stdcall hWin:HWND
	LOCAL @hProcess:HANDLE
	LOCAL @dwPid:DWORD
	LOCAL @pShellcode:PBYTE
	LOCAL @dwWritten:DWORD
	LOCAL @hRemoteThread:DWORD
	LOCAL @dwOldProtect:DWORD
	; 初始化局部变量
	mov @hRemoteThread, 0
	mov @hProcess, NULL
	mov @pShellcode, NULL
	mov @dwWritten, 0
	mov @dwPid, 0
	; 获取MessageBoxA的地址
	invoke VirtualProtect, INJECT_CODE, 64, PAGE_EXECUTE_READWRITE, addr @dwOldProtect
	invoke GetModuleHandle, offset g_szUser32
	invoke GetProcAddress, eax, offset g_szMsgBox
	mov g_pfnMessageBoxA, eax
	invoke VirtualProtect, INJECT_CODE, 64, addr @dwOldProtect, addr @dwOldProtect
	; 获取目标进程PID
	invoke GetDlgItemInt, hWin, IDC_EDT_PID, FALSE, FALSE
	mov @dwPid, eax
	test eax, eax 
	jz ENDFUNC
	; 打开目标进程
	invoke OpenProcess, PROCESS_ALL_ACCESS, FALSE, @dwPid
	mov @hProcess, eax
	test eax, eax 
	jz ENDFUNC
	; 在目标进程内分配空间 
	invoke VirtualAllocEx, @hProcess, NULL, g_ddShellcodeSize, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE
	mov @pShellcode, eax
	test eax, eax
	jz ENDFUNC
	; 把shellcode写入目标进程
	invoke WriteProcessMemory, @hProcess, @pShellcode, INJECT_CODE, g_ddShellcodeSize, addr @dwWritten
	test eax, eax
	jz ENDFUNC
	; 创建远程线程
	invoke CreateRemoteThread, @hProcess, NULL, 0, @pShellcode, NULL, 0, NULL
	mov @hRemoteThread, eax
	test eax, eax
	jz ENDFUNC
	invoke Sleep, 500
ENDFUNC:
	cmp @hRemoteThread, 0
	jz @F
	invoke CloseHandle, @hRemoteThread
	mov @hRemoteThread, 0
@@:
	cmp @hProcess, 0
	jz @F
	invoke CloseHandle, @hProcess
	mov @hProcess, 0
@@:
	ret

InjectObject endp


DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

	mov		eax,uMsg
	.if eax==WM_INITDIALOG
	
	.elseif eax==WM_COMMAND
		mov eax, wParam
		cmp ax, IDC_BTN_BROWSE
		jnz @F
		; 获取目标进程PID
		invoke GetPidByProcessName, hWin 
		invoke SetDlgItemInt, hWin, IDC_EDT_PID, eax, FALSE
		test eax, eax
		jz NOEXEC
		mov eax, TRUE
		ret
@@:
		cmp ax, IDC_BTN_INJECT
		jnz NOEXEC
		invoke InjectObject, hWin
		test eax, eax
		jz NOEXEC
		invoke SetDlgItemText, hWin, IDC_STATIC_STATUS, offset g_szOk
		mov eax, TRUE
		ret
NOEXEC:
		invoke SetDlgItemText, hWin, IDC_STATIC_STATUS, offset g_szFail
		mov eax, FALSE
		ret 
	.elseif eax==WM_CLOSE
		invoke EndDialog,hWin,0
	.else
		mov		eax,FALSE
		ret
	.endif
	mov		eax,TRUE
	ret

DlgProc endp

end start

运行如下:
代码重定位技术-LMLPHP
(完)

07-28 11:24