【32asm】04 - 重定位

Lot·AWM發表於2023-01-06

目標:在掃雷中注入一個messagebox彈窗;

方法:開啟一個程式(掃雷的程式),申請記憶體,寫入messagebox;

另外啟動一個執行緒,讓整個程式碼跑起來

專案建立

【32asm】04 - 重定位

【32asm】04 - 重定位

注入程式碼

.586
.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
    g_szWinmine db "掃雷", 0
    g_szKernel db "Kernel32", 0
    g_szLoadLibrary db "LoadLibraryA", 0
    g_szGetProcAddress db "GetProcAddress", 0
    g_hKer   dd 0
    g_dwPid   dd 0
    g_hProc   dd 0
    g_pAddr   dd 0
    g_dwBytesWrited dd 0
    g_dwOldProc dd 0 
    g_szMsg   db "你被注入了", 0
    g_szTitle db "不要擔心,重啟就行", 0
    
    
.code

MSGBOX:
int 3
invoke MessageBox,NULL,offset g_szMsg,offset g_szTitle, MB_OK

    

start:
    ;開啟程式
    invoke FindWindow,NULL,offset g_szWinmine           ;視窗控制程式碼
    invoke GetWindowThreadProcessId,eax,offset g_dwPid  ; 程式id
    invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,g_dwPid ;開啟程式
	mov g_hProc,eax
	
	;申請記憶體
    invoke VirtualAllocEx,g_hProc,NULL,1000h,MEM_COMMIT,PAGE_EXECUTE_READWRITE
    mov g_pAddr,eax
    
    
    ;生成機器碼寫入到申請的記憶體,跨程式寫記憶體
    invoke WriteProcessMemory, g_hProc, g_pAddr, offset MSGBOX, offset start - offset MSGBOX, offset g_dwBytesWrited
	
	; 建立執行緒,執行程式碼
	invoke CreateRemoteThread,g_hProc,NULL,0,g_pAddr,NULL,NULL,NULL
	
	invoke ExitProcess,eax
	end start

掃雷的可執行檔案放進去,先執行了掃雷,在執行程式,導致直接掃雷崩潰,,,,,,,,

除錯分析過程記錄

在chongdingwei.exe中記憶體申請成功,在02770000處;

在winmine.exe中找到這個位置檢視,4個push和1個call;

在chongdingwei.exe再檢視

【32asm】04 - 重定位

檢視chongdingwei.exe,找到二進位制資料,4個push(00結尾)和1個call;

【32asm】04 - 重定位

在winmine.exe的02770000處下斷點,當chongdingwei.exe啟動執行緒時,在這個位置斷下來

【32asm】04 - 重定位

這裡重新開始跑了,申請的地址變了,不過不影響分析,繼續進行,新申請的地址 02b60000

當chongdingwei.exe啟動執行緒

【32asm】04 - 重定位

在winmine.exe的02770000處這個位置斷下來;

【32asm】04 - 重定位

繼續單步走一下就崩潰了; 這裡是怎麼看出來崩掉的 ?????????

檢視日誌: 檢視 - 記錄

這裡日誌沒有報錯資訊

【32asm】04 - 重定位

用x64dbg開啟調一下,這裡的日誌資訊比較詳細;

winmine.exe用x64dbg開啟,先讓程式跑起來;

在radasm生成程式碼的前面加個int 3,當斷點用,到int3的時候偵錯程式就會停下來的,就能知道下斷點的位置;

radasm中 構建-執行,主執行緒呼叫,winmine.exe在x64dbg斷下來

【32asm】04 - 重定位

【32asm】04 - 重定位

f8單步,直接崩潰;

【32asm】04 - 重定位

下個斷點,(將斷點int 3,改為Nop, 繼續走)

【32asm】04 - 重定位

走到call的位置就掛掉了

4個push,中間兩個是兩個字串: 右鍵-記憶體視窗中轉到-這個地址 ;發現並不是傳入的字串

字串沒有複製過來,而且地址不對,地址在原程式中寫成固定值了;

【32asm】04 - 重定位

這個字串地址是原程式中的地址,並沒有複製到winmine.exe中

開啟chongdingwei.exe,看一下字串的位置

【32asm】04 - 重定位

【32asm】04 - 重定位

檢視字串: 右鍵 - 資料視窗跟隨 - 立即數

【32asm】04 - 重定位

分析完成,開始處理問題;

問題處理

字串問題處理: 先把字串帶到winmine.exe執行緒:

修改用這種方式

【32asm】04 - 重定位

先讓winmine.exe用x64dbg開啟,程式跑起來;

雙擊chongdingwei.exe

程式斷下來

【32asm】04 - 重定位

下斷點,檢視字串是否帶進來了

字串從02ac0003開始的

【32asm】04 - 重定位

可以看到字串代進來了;

但是push的地址不對,push的地址應該是在jmp的位置;

因為這個地址是寫的注入程式碼時記憶體的地址,複製到主執行緒後,機器碼沒有變化,這個地址還是 原來的地址。

地址需要動態算出來

【32asm】04 - 重定位

地址問題處理:發現主執行緒地址與注入程式碼地址差是一樣的(偏移值相同)。 動態算出來地址

當程式碼跑起來的時候,需要算出來在哪個地址;

用相同指令位置的值來相減就可以;

偏移值: 獲取當前的EIP ,減去之前的offset地址值

【32asm】04 - 重定位

獲取當前指令在新的記憶體中地址:

call 會把下一條指令的地址壓棧,標號正好在pop指令上,所以就把pop ebx指令地址壓棧,然後再執行pop ebx,此時ebx就是這條指令的地址(eip的值);

獲取偏移:

新地址 - 原先的地址

【32asm】04 - 重定位

invoke不能用了,否則地址仍然是固定的,但地址要實時取,所以用push四個引數。

【32asm】04 - 重定位

先讓winmine.exe用x64dbg開啟,程式跑起來;

雙擊chongdingwei.exe

程式斷下來,可以看到各個差值是正確的

【32asm】04 - 重定位

但是這個call的地址值為空,這裡無法呼叫messagebox

messagebox地址也不能寫死,否則不能做到通用;

【32asm】04 - 重定位

看一下chongdingwei.exe的call怎麼呼叫messagebox的

call 跑到jmp的位置,jmp跳到messagebox函式地址的,是一個偏移

【32asm】04 - 重定位

【32asm】04 - 重定位

同一臺電腦上,不同程式中的dll地址相同,包括kernal32,user32,那麼LoadLib,GetProcAddr,地址也是一樣的; 模組地址一樣,那麼匯出函式地址一樣

假設不同程式中地址不一樣,獲取到LoadLibary,GetProcAddress地址,就獲取任何api的地址

未使用宏的時候,程式碼儲存一下

.586
.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

spush macro x
    mov eax, offset x
    add eax,ebx
    push eax
endm

scall macro x
    mov eax, offset x
    add eax,ebx
    call dword ptr[eax]
endm

smov macro x,reg
    mov eax, offset x
    add eax,ebx
    mov dword ptr [eax],reg
endm



.data
    g_szWinmine db "掃雷", 0
    g_szKernel db "Kernel32", 0
    g_szLoadLibrary db "LoadLibraryA", 0
    g_szGetProcAddress db "GetProcAddress", 0
    g_hKer   dd 0
    g_dwPid   dd 0
    g_hProc   dd 0
    g_pAddr   dd 0
    g_dwBytesWrited dd 0
    g_dwOldProc dd 0 


.code

MSGBOX:
int 3

jmp COMEONBABY
g_szMsg   db "你被注入了", 0
g_szTitle db "不要擔心,重啟就行", 0
g_szUser32 db "user32",0  ;拿到user32基址
g_szMsgBox db "MessageBoxA",0

g_pfnLoadLib   dd 0
g_pfnGetProcAddr dd 0
g_pfnMessageBox dd 0
g_hUser32    dd 0

COMEONBABY:
call NEXT
NEXT:
pop ebx    ; 獲取新記憶體地址
sub ebx, offset NEXT ;獲取偏移

mov edx, offset g_pfnLoadLib
add edx,ebx ;LoadLibary地址

mov eax, offset g_szUser32
add eax, ebx
push eax

call dword ptr [edx]; 呼叫LoadLibary,載入User32模組

mov edx, offset g_hUser32
add edx,ebx
mov dword ptr [edx],eax

mov edx, offset g_pfnGetProcAddr
add edx,ebx ;GetProcAddress地址

mov eax, offset g_szMsgBox
add eax,ebx
push eax 

call dword ptr[eax] ;呼叫GetProcAddress,獲取MessageBox地址

mov edx, offset g_pfnMessageBox
add edx, ebx
mov dword ptr [edx], eax

push MB_OK

mov eax, offset g_szTitle
add eax,ebx  ;當前地址+偏移地址
push eax

mov eax, offset g_szMsg
add eax,ebx 
push eax

push NULL


mov edx, offset g_pfnMessageBox
add edx, ebx
call dword ptr [edx] ; 呼叫MessageBox

ret 4 ; 執行之後從執行緒函式中返回,執行緒函式一個引數,引數平棧

;invoke MessageBox,NULL,offset g_szMsg,offset g_szTitle, MB_OK

    

start:
    ;開啟程式
    invoke FindWindow,NULL,offset g_szWinmine           ;視窗控制程式碼
    invoke GetWindowThreadProcessId,eax,offset g_dwPid  ; 程式id
    invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,g_dwPid ;開啟程式
	mov g_hProc,eax
	
	;申請記憶體
    invoke VirtualAllocEx,g_hProc,NULL,1000h,MEM_COMMIT,PAGE_EXECUTE_READWRITE
    mov g_pAddr,eax
    
    
    ;生成機器碼寫入到申請的記憶體,跨程式寫記憶體
    invoke WriteProcessMemory, g_hProc, g_pAddr, offset MSGBOX, offset start - offset MSGBOX, offset g_dwBytesWrited
	
	; 建立執行緒,執行程式碼
	invoke CreateRemoteThread,g_hProc,NULL,0,g_pAddr,NULL,NULL,NULL
	
	invoke ExitProcess,eax

end start

使用宏程式碼記錄

.586
.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

spush macro x
    mov eax, offset x
    add eax,ebx
    push eax
endm

scall macro x
    mov eax, offset x
    add eax,ebx
    call dword ptr[eax]
endm

smov macro x,reg
    mov eax, offset x
    add eax,ebx
    mov dword ptr [eax],reg
endm



.data
    g_szWinmine db "掃雷", 0
    g_szKernel db "Kernel32", 0
    g_szLoadLibrary db "LoadLibraryA", 0
    g_szGetProcAddress db "GetProcAddress", 0
    g_hKer   dd 0
    g_dwPid   dd 0
    g_hProc   dd 0
    g_pAddr   dd 0
    g_dwBytesWrited dd 0
    g_dwOldProc dd 0 


.code

MSGBOX:
int 3

jmp COMEONBABY
g_szMsg   db "你被注入了", 0
g_szTitle db "不要擔心,重啟就行", 0
g_szUser32 db "user32",0  ;拿到user32基址
g_szMsgBox db "MessageBoxA",0


g_pfnLoadLib   dd 0
g_pfnGetProcAddr dd 0
g_pfnMessageBox dd 0
g_hUser32    dd 0

COMEONBABY:
call NEXT
NEXT:
pop ebx    ; 獲取新記憶體地址
sub ebx, offset NEXT ;獲取偏移


;載入user32.dll
spush offset g_szUser32
scall g_pfnLoadLib

mov edx,eax
smov g_hUser32,edx


;獲取MessageBox地址
spush offset g_szMsgBox
scall g_pfnGetProcAddr

mov edx,eax
smov g_pfnMessageBox,edx


;呼叫MessageBox
push MB_OK
spush offset g_szTitle
spush offset g_szMsg
push NULL
scall offset g_pfnMessageBox

ret 4 ; 執行之後從執行緒函式中返回,執行緒函式一個引數,引數平棧

;invoke MessageBox,NULL,offset g_szMsg,offset g_szTitle, MB_OK

    

start:
    ;開啟程式
    invoke FindWindow,NULL,offset g_szWinmine           ;視窗控制程式碼
    invoke GetWindowThreadProcessId,eax,offset g_dwPid  ; 程式id
    invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,g_dwPid ;開啟程式
	mov g_hProc,eax
	
	;寫入loadLibrary和GetProcAddress地址
	invoke GetModuleHandle,offset g_szKernel
	mov g_hKer,eax
	
	invoke GetProcAddress,g_hKer,offset g_szLoadLibrary
	mov g_pfnLoadLib,eax
	
	invoke GetProcAddress,g_hKer,offset g_szGetProcAddress
	mov g_pfnGetProcAddr,eax
	
	
	
	
	
	;申請記憶體
    invoke VirtualAllocEx,g_hProc,NULL,1000h,MEM_COMMIT,PAGE_EXECUTE_READWRITE
    mov g_pAddr,eax
    
    
    ;生成機器碼寫入到申請的記憶體,跨程式寫記憶體
    invoke WriteProcessMemory, g_hProc, g_pAddr, offset MSGBOX, offset start - offset MSGBOX, offset g_dwBytesWrited
	
	; 建立執行緒,執行程式碼
	invoke CreateRemoteThread,g_hProc,NULL,0,g_pAddr,NULL,NULL,NULL
	
	invoke ExitProcess,eax

end start

地址寫資料的時候報C00005,401034程式碼區,地址寫到程式碼區就完蛋

程式碼需要改一下屬性

【32asm】04 - 重定位

主程式也報錯異常了;

發現

【32asm】04 - 重定位

引數不夠的表現

程式碼修改,messageBox增加引數

spush offset g_szMsgBox

spushval g_hUser32

scall g_pfnGetProcAddr

【32asm】04 - 重定位

注入成功

【32asm】04 - 重定位

完整程式碼記錄

.586
.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
spush macro x
    mov eax, offset x
    add eax, ebx
    push eax
endm

spushval macro x
    mov eax, offset x
    add eax, ebx
    push dword ptr[eax]
endm

scall macro x
    mov eax, offset x
    add eax, ebx
    call dword ptr[eax]
endm

smov macro x, reg
    mov eax, offset x
    add eax, ebx
    mov dword ptr [eax], reg
endm

.data

g_szWinmine db "掃雷", 0
g_szKernel db "Kernel32", 0
g_szLoadLibrary db "LoadLibraryA", 0
g_szGetProcAddress db "GetProcAddress", 0
g_hKer   dd 0
g_dwPid   dd 0
g_hProc   dd 0
g_pAddr   dd 0
g_dwBytesWrited dd 0
g_dwOldProc dd 0 

.code
MSGBOX:

jmp EXECODE
g_szMsg   db "你被注入了", 0
g_szTitle db "不要擔心,重啟就行", 0

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

g_pfnLoadLib        dd 0 ;三個函式地址,在主函式賦值了。
g_pfnGetProcAddr    dd 0
g_pfnMessageBox     dd 0

g_hUser32           dd 0 ;控制程式碼


EXECODE:

call NEXT
NEXT:
pop ebx
sub ebx,offset NEXT  ;獲取偏移

;----------------------------------------messagebox函式在user32.dll裡-------------------
;載入user32.dll
spush offset g_szUser32
scall g_pfnLoadLib

mov edx, eax
smov g_hUser32, edx

;獲取MessageBox地址
spush   offset g_szMsgBox
spushval g_hUser32
scall g_pfnGetProcAddr

mov edx, eax
smov g_pfnMessageBox, edx

;----------------------------------------呼叫messagebox函式-------------------
push MB_OK
spush offset g_szMsg
spush offset g_szTitle
push NULL
scall offset g_pfnMessageBox
ret 4                 ;執行緒過程函式有一個引數
;invoke MessageBox, NULL, offset g_szMsg, offset g_szTitle, MB_OK
;---------------------------------------------------------------------------------


start:
	
    invoke FindWindow,NULL,offset g_szWinmine  ;視窗控制程式碼,返回到了eax
    invoke GetWindowThreadProcessId,eax,offset g_dwPid ;程式id
    invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,g_dwPid ;開啟程式
    mov g_hProc,eax                                    ;程式控制程式碼
    
    ;改程式碼段屬性
    invoke VirtualProtect, offset MSGBOX, offset start - offset MSGBOX, PAGE_EXECUTE_READWRITE, offset g_dwOldProc
    
    
    ;寫入LoadLibaray和GetProcAddress地址;LoadLibaray載入user32.dll,GetProcAddress得到messagebox地址。
    invoke GetModuleHandle, offset g_szKernel
    mov g_hKer, eax
    
    invoke GetProcAddress,g_hKer,offset g_szLoadLibrary
    mov g_pfnLoadLib, eax
    
    invoke GetProcAddress, g_hKer, offset g_szGetProcAddress
    mov g_pfnGetProcAddr, eax
    
    ;申請記憶體
    invoke VirtualAllocEx,g_hProc,NULL,1000h,MEM_COMMIT,PAGE_EXECUTE_READWRITE
    mov g_pAddr,eax
    
    invoke VirtualProtect, offset MSGBOX, offset start - offset MSGBOX, g_dwOldProc, offset g_dwOldProc
    
    ;寫入機器碼
    invoke WriteProcessMemory,g_hProc,g_pAddr,offset MSGBOX, offset start - offset MSGBOX, offset g_dwBytesWrited
    
    ;建立執行緒,執行程式碼
    invoke CreateRemoteThread, g_hProc, NULL,0, g_pAddr, NULL, NULL, NULL
    
	invoke ExitProcess,eax


end start