前言

在我们日常编程中,有可能为的只是一个函数的调用的情况,导致我们需要写一个DLL注入到目标进程中。就笔者个人而言,笔者更喜欢集成在一个EXE中。所以这个时候最好的解决方式就是ShellCode。而外面已有的Shellcode编写大部分都是最终生成二进制数据,我个人认为是比较麻烦的。所以这里我带来了一个另类思路。

编写方式

1、构造一个结构体,里面用来填充ShellCode所需要内容。切记禁止有需要间接访问的内容。

1
2
3
4
5
6
7
8
using MessageBoxW_t = INT(WINAPI*)(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType);

struct ShellCodeInfo {
MessageBoxW_t MessageBoxW;
const wchar_t* szText;
const wchar_t* szCaption;
UINT uType;
};

2、组装参数并把结构体写入到目标进程中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 组装参数
ShellCodeInfo shellcodeInfo{};
shellcodeInfo.MessageBoxW = (MessageBoxW_t)MessageBoxW;
const wchar_t szText[]{ L"测试ShellCode" };
const wchar_t szCaption[]{ L"标题" };
memcpy_s((void*)shellcodeInfo.szText, sizeof shellcodeInfo.szText, szText, sizeof szText);
memcpy_s((void*)shellcodeInfo.szCaption, sizeof shellcodeInfo.szCaption, szCaption, sizeof szCaption);
shellcodeInfo.uType = MB_OK;

// 将参数映射到目标进程
LPBYTE lpParamBuff = reinterpret_cast<BYTE*>(VirtualAllocEx(hProcess, nullptr, sizeof(ShellCodeInfo), MEM_COMMIT MEM_RESERVE, PAGE_READWRITE));
if (!lpParamBuff) {
break;
}
if (!WriteProcessMemory(hProcess, lpParamBuff, &shellcodeInfo, sizeof(ShellCodeInfo), nullptr)) {
break;
}

3、准备一个函数,用来当作ShellCode函数。切记禁止写与地址相关的代码。

1
2
3
4
DWORD RemoteMessageBox(ShellCodeInfo* shellcodeInfo) {
shellcodeInfo->MessageBoxW(NULL, shellcodeInfo->szText, shellcodeInfo->szCaption, shellcodeInfo->uType);
return 0;
}

4、将函数当作ShellCode写入目标进程中

1
2
3
4
5
6
7
8
// 写入shellcode
LPVOID lpShellcode = VirtualAllocEx(hProcess, nullptr, 0x1000, MEM_COMMIT MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!lpShellcode) {
break;
}
if (!WriteProcessMemory(hProcess, lpShellcode, RemoteMessageBox, 0x1000, nullptr)) {
break;
}

5、使用远线程调用该函数

1
2
3
4
5
6
7
// 远线程执行shellcode
HANDLE hThread = CreateRemoteThread(hProcess, nullptr, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(lpShellcode), lpParamBuff, 0, nullptr);
if (!hThread) {
break;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);

6、禁用安全检查,防止出现地址相关代码
2022-12-15T17:05:24.png

问题

该方法使用ShellCode不能在默认的Debug模式下运行,因为Debug模式下会对函数生成与地址有关的代码,所以会导致在目标进程中崩溃。而我们日常开发中可能需要调试其他代码,这就产生了冲突。

解决方案

1、对函数使用static字段修饰,消除跳转表
2、使用调试库设置为否【英文叫Use Debug Libraries】

l5hv80t5.png

3、支持仅我的代码调试设置为否【英文叫Support Just My Code Debugging】

l5hv8tqr.png

写在最后

如果本文对你有所帮助,请麻烦点赞转发。如果你有更好的Debug模式下保持shellcode干净方式,请留言哦