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

思路:将主线程挂起后获取到主线程的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 }

 

转载于:https://www.cnblogs.com/peng-lei/articles/5187111.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Kotlin 中,我们可以通过函数封装的方式来简化在线程和子线程之间的切换。下面是一个简单的示例: ```kotlin import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext /** * 在子线程中执行耗时任务,然后在线程中进行 UI 更新。 * * @param block 耗时任务的执行代码块。 * @param uiBlock UI 更新的执行代码块。 */ fun runOnIoThenMain(block: suspend () -> Any?, uiBlock: (result: Any?) -> Unit) { GlobalScope.launch(Dispatchers.IO) { // 在子线程中执行耗时任务 val result = block() // 切换到线程更新 UI withContext(Dispatchers.Main) { uiBlock(result) } } } ``` 在上面的代码中,我们封装了一个名为 `runOnIoThenMain` 的函数。该函数接受两个参数:一个是耗时任务的代码块 `block`,另一个是 UI 更新的代码块 `uiBlock`。在函数内部,我们使用 `GlobalScope.launch` 创建一个协程,并指定了 `Dispatchers.IO` 作为协程的上下文。在协程中执行耗时任务后,我们使用 `withContext(Dispatchers.Main)` 切换到线程进行 UI 更新。 使用该函数的示例代码如下所示: ```kotlin // 在子线程中执行网络请求,然后在线程中更新 UI runOnIoThenMain({ doNetworkRequest() }, { result -> updateUI(result) }) ``` 在上面的代码中,我们将网络请求的代码块 `doNetworkRequest` 作为 `block` 参数传递给了 `runOnIoThenMain` 函数,将 UI 更新的代码块 `updateUI` 作为 `uiBlock` 参数传递给了该函数。函数内部会在子线程中执行 `doNetworkRequest`,然后在线程中执行 `updateUI`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值