主线程调用(通过修改线程上下文实现)

思路:将主线程挂起后获取到主线程的eip,然后将eip修改为shellcode的地址恢复线程运行,当shellcode执行完成后跳转到旧eip处继续执行。

 1 typedef VOID(__stdcall *PFN_CALL)(const VOID *pvIn, VOID *pvOut);
 2 
 3 BOOL CallForThread(DWORD dwThreadId, PFN_CALL pfnCall, const VOID *pvIn, VOID *pvOut)
 4 {
 5     _ASSERT(pfnCall != NULL);
 6     _ASSERT(dwThreadId != ::GetCurrentThreadId());
 7 
 8     // 打开线程
 9     HANDLE hThread = ::OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId);
10 
11     if (hThread == NULL)
12     {
13         return FALSE;
14     }
15 
16     // 获取线程上下文
17     CONTEXT context = { 0 };
18 
19     ::SuspendThread(hThread);
20     context.ContextFlags = CONTEXT_ALL;
21     ::GetThreadContext(hThread, &context);
22 
23     // 申请shellcode空间
24     VOID *pvShellCode = ::VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
25 
26     if (pvShellCode == NULL)
27     {
28         ::ResumeThread(hThread);
29         ::CloseHandle(hThread);
30         hThread = NULL;
31 
32         return FALSE;
33     }
34 
35     // 填充shellcode
36     DWORD dwExecuteFinishFlag = 0;
37     BYTE bShellCode[] = {
38         0x60,                                                       // pushad
39         0x68, 0x00, 0x00, 0x00, 0x00,                               // push pvOut
40         0x68, 0x00, 0x00, 0x00, 0x00,                               // push pvIn
41         0xB8, 0x00, 0x00, 0x00, 0x00,                               // mov eax, pfnCall
42         0xFF, 0xD0,                                                 // call eax
43         0xC7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // mov dword ptr [执行完成标志指针], 1
44         0x61,                                                       // popad
45         0x68, 0x00, 0x00, 0x00, 0x00,                               // push 线程旧Eip
46         0xC3                                                        // ret
47     };
48 
49     *(DWORD *)(&bShellCode[2]) = (DWORD)pvOut;
50     *(DWORD *)(&bShellCode[7]) = (DWORD)pvIn;
51     *(DWORD *)(&bShellCode[12]) = (DWORD)pfnCall;
52     *(DWORD *)(&bShellCode[20]) = (DWORD)&dwExecuteFinishFlag;
53     *(DWORD *)(&bShellCode[30]) = context.Eip;
54     memcpy_s(pvShellCode, 0x1000, bShellCode, sizeof (bShellCode));
55 
56     // 修改Eip执行
57     context.Eip = (DWORD)pvShellCode;
58     context.ContextFlags = CONTEXT_ALL;
59     ::SetThreadContext(hThread, &context);
60     ::ResumeThread(hThread);
61     ::PostThreadMessage(dwThreadId, 0, (WPARAM)0, (LPARAM)0);
62 
63     // 等待执行完成标志置位
64     while (dwExecuteFinishFlag == 0)
65     {
66         ::Sleep(10);
67     }
68 
69     // 判断ShellCode代码是否全部执行完成
70     DWORD dwShellCodeBeg = (DWORD)pvShellCode;
71     DWORD dwShellCodeEnd = (DWORD)pvShellCode + sizeof (bShellCode)-1;
72 
73     while (TRUE)/*while-1*/
74     {
75         // 获取Eip
76         context.ContextFlags = CONTEXT_ALL;
77         ::GetThreadContext(hThread, &context);
78 
79         // 检查当前Eip是否在shellcode中
80         if (context.Eip < dwShellCodeBeg || context.Eip > dwShellCodeEnd)
81         {
82             break;
83         }
84         else
85         {
86             ::Sleep(10);
87         }
88     }/*end of while-1*/
89 
90     ::VirtualFree(pvShellCode, 0x1000, MEM_FREE);
91     pvShellCode = NULL;
92     ::CloseHandle(hThread);
93     hThread = NULL;
94 
95     return TRUE;
96 }

 

posted @ 2016-02-12 16:11  狂奔的鸡骨架  阅读(603)  评论(0编辑  收藏  举报
AmazingCounters.com