Reputation: 1
CreateRemoteThread()
fails with error 5 when calling inject_param->allocate()
in inject_begin()
. Comment it and CreateRemoteThread()
is OK. I dont know why. The target platform is 64-bit.
#include <iostream>
#include <windows.h>
#include <TlHelp32.h>
std::uint32_t get_process_id(
__in const std::basic_string<TCHAR>& name) {
PROCESSENTRY32 process_entry;
process_entry.dwSize = sizeof(PROCESSENTRY32);
auto process_snapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(process_snapshot, &process_entry))
{
do {
if (!wcscmp(process_entry.szExeFile, name.data()))
{
CloseHandle(process_snapshot);
return process_entry.th32ProcessID;
}
} while (Process32Next(process_snapshot, &process_entry));
}
CloseHandle(process_snapshot);
return 0;
}
void adjust_token_privileges() {
HANDLE h_token = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &h_token))
{
return;
}
TOKEN_PRIVILEGES priv = { 0 };
priv.PrivilegeCount = 1;
priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid))
{
AdjustTokenPrivileges(h_token, FALSE, &priv, 0, NULL, NULL);
}
CloseHandle(h_token);
}
typedef NTSTATUS(WINAPI* NTALLOCATEVIRTUALMEMORY)(IN HANDLE ProcessHandle, IN OUT PVOID* BaseAddress, IN ULONG ZeroBits, IN OUT PSIZE_T RegionSize, IN ULONG AllocationType, IN ULONG Protect);
struct InjectParam {
int age;
NTALLOCATEVIRTUALMEMORY allocate;
};
//shell code
ULONG_PTR WINAPI inject_begin(InjectParam* inject_param) {
inject_param->age += 1;//age=2
PVOID memory_address = NULL;
SIZE_T size = 10;
//comment it CreateRemoteThread is ok
inject_param->allocate((HANDLE)-1, &memory_address, 0, &size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
return 0;
}
void inject_end() {
printf("11");
}
void remote_map_load_dll(HANDLE target_process)
{
InjectParam inject_param;
//将指定内存区域的内容清零
RtlZeroMemory(&inject_param, sizeof(inject_param));
inject_param.age = 1;
//-------------------------------
WORD* shell_code_begin = (WORD*)inject_begin;
DWORD shell_code_size = 0;
while (*shell_code_begin != 0XCCCC)
{
shell_code_begin++;
shell_code_size += 2;
}
printf("shellcode length:%d\n", shell_code_size);
PVOID shell_code_buffer = malloc(shell_code_size);
RtlCopyMemory(shell_code_buffer, inject_begin, shell_code_size);
//-------------------------------
//获取本进程的 ntdll.dll
HMODULE h_nt_dll = GetModuleHandleA("ntdll.dll");
inject_param.allocate = (NTALLOCATEVIRTUALMEMORY)GetProcAddress(h_nt_dll, "NtAllocateVirtualMemory");
printf("NtAllocateVirtualMemory address :0x%p\r\n", inject_param.allocate);
//-------------------------------
PBYTE shellcode_address = (PBYTE)VirtualAllocEx(target_process, 0, shell_code_size + sizeof(inject_param), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// printf("shellcode_address:0x%p\r\n", shellcode_address);
//-------------------------------write shell code
SIZE_T dw_writed = 0;
PBYTE shell_code_address = shellcode_address;
printf("shell_code_address:0X%p\r\n", shell_code_address);
WriteProcessMemory(target_process, shell_code_address, shell_code_buffer, shell_code_size, &dw_writed);
printf("write ShellCodeAddress bytes:%d\r\n", dw_writed);
//------------------------------- write InjectParam
PBYTE inject_param_address = shellcode_address + shell_code_size;
printf("InjectParamAddress:0X%p\r\n", inject_param_address);
BOOL result = WriteProcessMemory(target_process, (LPVOID)inject_param_address, &inject_param, sizeof(inject_param), &dw_writed);
printf("write InjectParamAddress bytes:%d\r\n", dw_writed);
//-------------------------------
HANDLE remote_thread = CreateRemoteThread(target_process, 0, 0, (LPTHREAD_START_ROUTINE)shell_code_address, inject_param_address, 0, 0);
printf("remote_thread:0x%X\n", remote_thread);
if (remote_thread)
{
WaitForSingleObject(remote_thread, -1);
//ERROR_ACCESS_DENIED=0x5
DWORD exit_code = 0;
GetExitCodeThread(remote_thread, &exit_code);
printf("error:0x%x\n", exit_code);
//释放申请的内存
VirtualFreeEx(target_process, shellcode_address, 0, MEM_FREE);
CloseHandle(remote_thread);
}
//free
free(shell_code_buffer);
}
int main() {
int result = EXIT_SUCCESS;
//
adjust_token_privileges();
//get dwmpid
auto dwm_pid = get_process_id(L"CalculatorApp.exe");
auto h_handle = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwm_pid);
printf("dwmpid:%d\r\n", dwm_pid);
//
remote_map_load_dll(h_handle);
CloseHandle(h_handle);
system("pause");
return result;
}
Upvotes: -4
Views: 84
Reputation: 33754
Comment it and
CreateRemoteThread()
is OK.
not need confuse result of CreateRemoteThread(..)
and thread exit code, returned by GetExitCodeThread
. these are completely different things. and if you write such code - this is mandatory (and trivial) trace it under debugger, in both source and target process, to view exactly what happense, and where error, if any. and at least clearly formulate where the error is and show the actual code. you not check, what error return CreateRemoteThread
, if it fail (i assume it not fail). exit_code
is ERROR_ACCESS_DENIED=0x5
? but in your current code inject_begin
uncodtitionally return 0. even if NtAllocateVirtualMemory
fail. even if your actual code is return inject_param->allocate(..)
- this api return NTSTATUS
not win32 error code ERROR_ACCESS_DENIED
. so unclear from where you at all can got it. your current code can not got this code.
VirtualFreeEx(target_process, shellcode_address, 0, MEM_FREE);
not free memore, MEM_RELEASE
must be used in place MEM_FREE
.
no any sense, in current code, copy your code to temporary buffer, shell_code_buffer
, for what ?! but exist sense copy shell code and data to single buffer, for do 1 call to, WriteProcessMemory
instead 2 calls. but you not do this.
while (*shell_code_begin != 0XCCCC)
the code size is not determined that way
You can't allocate
PAGE_EXECUTE_READWRITE
memory on recent Windows systems. It's blocked by the "Data Execution Protection" code, mostly to prevent what you're trying to do here.
you can not allocate it when call this api from process with ProhibitDynamicCode
mitigation. NtAllocateVirtualMemory
return STATUS_DYNAMIC_CODE_BLOCKED
in this case. when called from this process. however this is not ERROR_ACCESS_DENIED
and even not it win32 convert, ERROR_DYNAMIC_CODE_BLOCKED
code can look like:
struct InjectParam {
NTSTATUS (NTAPI* NtAllocateVirtualMemory)(
_In_ HANDLE ProcessHandle,
_Inout_ PVOID* BaseAddress,
_In_ ULONG ZeroBits,
_Inout_ PSIZE_T RegionSize,
_In_ ULONG AllocationType,
_In_ ULONG Protect);
int age = 0;
UCHAR code[];
#pragma code_seg(".text$mn$sc$0")
static ULONG WINAPI inject_begin(InjectParam* This)
{
return This->inject();
}
#pragma code_seg(".text$mn$sc$1")
ULONG inject()
{
age++;
SIZE_T size = 10;
PVOID memory_address = NULL;
return NtAllocateVirtualMemory(NtCurrentProcess(), &memory_address, 0, &size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
}
#pragma code_seg(".text$mn$sc$2")
static ULONG code_size()
{
return (ULONG)((ULONG_PTR)code_size - (ULONG_PTR)inject_begin);
}
#pragma code_seg()
void* operator new(size_t s){
return LocalAlloc(LMEM_FIXED, s + code_size());
}
void operator delete(void* pv) {
LocalFree(pv);
}
InjectParam() {
memcpy(code, inject_begin, code_size());
}
InjectParam(InjectParam* p);
BOOL Init()
{
if (HMODULE h_nt_dll = GetModuleHandleW(L"ntdll.dll"))
{
if ((void*&)NtAllocateVirtualMemory = GetProcAddress(h_nt_dll, "NtAllocateVirtualMemory"))
{
return TRUE;
}
}
return FALSE;
}
};
void remote_map_load_dll(HANDLE target_process)
{
if (InjectParam* inject_param = new InjectParam)
{
if (inject_param->Init())
{
SIZE_T shell_code_size = sizeof(InjectParam) + InjectParam::code_size();
if (PVOID shell_code_address = VirtualAllocEx(target_process,
0, shell_code_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
{
if (WriteProcessMemory(target_process, shell_code_address, inject_param, shell_code_size, &shell_code_size))
{
if (HANDLE remote_thread = CreateRemoteThread(target_process, 0, 0,
(LPTHREAD_START_ROUTINE)&reinterpret_cast<InjectParam*>(shell_code_address)->code,
shell_code_address, 0, 0))
{
if (WAIT_OBJECT_0 == WaitForSingleObject(remote_thread, INFINITE))
{
DWORD exit_code = 0;
if (GetExitCodeThread(remote_thread, &exit_code))
{
int age;
if (ReadProcessMemory(target_process,
&reinterpret_cast<InjectParam*>(shell_code_address)->age,
&age, sizeof(age), 0))
{
printf("age = %x, exit_code=%x\n", age, exit_code);
}
}
}
else
{
shell_code_address = 0;
}
CloseHandle(remote_thread);
}
}
VirtualFreeEx(target_process, shell_code_address, 0, MEM_RELEASE);
}
}
delete inject_param;
}
}
Upvotes: 0