目標:在掃雷中註入一個messagebox彈窗; 方法:打開一個進程(掃雷的進程),申請記憶體,寫入messagebox; 另外啟動一個線程,讓整個代碼跑起來 項目創建 註入代碼 .586 .model flat,stdcall option casemap:none include windows. ...
目標:在掃雷中註入一個messagebox彈窗;
方法:打開一個進程(掃雷的進程),申請記憶體,寫入messagebox;
另外啟動一個線程,讓整個代碼跑起來
項目創建
註入代碼
.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再查看
查看chongdingwei.exe,找到二進位數據,4個push(00結尾)和1個call;
在winmine.exe的02770000處下斷點,當chongdingwei.exe啟動線程時,在這個位置斷下來
這裡重新開始跑了,申請的地址變了,不過不影響分析,繼續進行,新申請的地址 02b60000
當chongdingwei.exe啟動線程
在winmine.exe的02770000處這個位置斷下來;
繼續單步走一下就崩潰了; 這裡是怎麼看出來崩掉的 ?????????
查看日誌: 查看 - 記錄
這裡日誌沒有報錯信息
用x64dbg打開調一下,這裡的日誌信息比較詳細;
winmine.exe用x64dbg打開,先讓進程跑起來;
在radasm生成代碼的前面加個int 3,當斷點用,到int3的時候調試器就會停下來的,就能知道下斷點的位置;
radasm中 構建-運行,主線程調用,winmine.exe在x64dbg斷下來
f8單步,直接崩潰;
下個斷點,(將斷點int 3,改為Nop, 繼續走)
走到call的位置就掛掉了
4個push,中間兩個是兩個字元串: 右鍵-記憶體視窗中轉到-這個地址 ;發現並不是傳入的字元串
字元串沒有拷貝過來,而且地址不對,地址在原進程中寫成固定值了;
這個字元串地址是原進程中的地址,並沒有拷貝到winmine.exe中
打開chongdingwei.exe,看一下字元串的位置
查看字元串: 右鍵 - 數據視窗跟隨 - 立即數
分析完成,開始處理問題;
問題處理
字元串問題處理: 先把字元串帶到winmine.exe線程:
修改用這種方式
先讓winmine.exe用x64dbg打開,程式跑起來;
雙擊chongdingwei.exe
程式斷下來
下斷點,查看字元串是否帶進來了
字元串從02ac0003開始的
可以看到字元串代進來了;
但是push的地址不對,push的地址應該是在jmp的位置;
因為這個地址是寫的註入代碼時記憶體的地址,拷貝到主線程後,機器碼沒有變化,這個地址還是 原來的地址。
地址需要動態算出來
地址問題處理:發現主線程地址與註入代碼地址差是一樣的(偏移值相同)。 動態算出來地址
當代碼跑起來的時候,需要算出來在哪個地址;
用相同指令位置的值來相減就可以;
偏移值: 獲取當前的EIP ,減去之前的offset地址值
獲取當前指令在新的記憶體中地址:
call 會把下一條指令的地址壓棧,標號正好在pop指令上,所以就把pop ebx指令地址壓棧,然後再執行pop ebx,此時ebx就是這條指令的地址(eip的值);
獲取偏移:
新地址 - 原先的地址
invoke不能用了,否則地址仍然是固定的,但地址要實時取,所以用push四個參數。
先讓winmine.exe用x64dbg打開,程式跑起來;
雙擊chongdingwei.exe
程式斷下來,可以看到各個差值是正確的
但是這個call的地址值為空,這裡無法調用messagebox
messagebox地址也不能寫死,否則不能做到通用;
看一下chongdingwei.exe的call怎麼調用messagebox的
call 跑到jmp的位置,jmp跳到messagebox函數地址的,是一個偏移
同一臺電腦上,不同進程中的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代碼區,地址寫到代碼區就完蛋
代碼需要改一下屬性
主進程也報錯異常了;
發現
參數不夠的表現
代碼修改,messageBox增加參數
spush offset g_szMsgBox
spushval g_hUser32
scall g_pfnGetProcAddr
註入成功
完整代碼記錄
.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