利用LdrLoadDll作为跳板,可以用其他api
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#include <winternl.h>
#define DEF_INJECT_MODULE "\\WorkCore.dll"
/*
*/
typedef NTSTATUS(NTAPI *pRtlInitUnicodeString)(PUNICODE_STRING, PCWSTR);
typedef NTSTATUS(NTAPI *pLdrLoadDll)(PWCHAR, ULONG, PUNICODE_STRING, PHANDLE);
typedef HANDLE(NTAPI *pRtlAddVectoredExceptionHandler)(ULONG, PVOID);
#pragma pack(push,1)
typedef struct _PARAM_DATA{
pRtlInitUnicodeString fnRtlInitUnicodeString;
pLdrLoadDll fnLdrLoadDll;
UNICODE_STRING UnicodeString;
WCHAR DllName[260];
PWCHAR DllPath;
ULONG Flags;
HANDLE ModuleHandle;
BYTE szBackupCode[50];
}PARAM_DATA, *PPARAM_DATA;
typedef struct _JMP_PATCH {
WORD REax; //B848 mov rax
UINT64 uAddress;
WORD JMP; //E0FF
}JMP_PATCH,*PJMP_PATCH;
#pragma pack(pop)
NTSTATUS NTAPI MyLdrLoadDll(PWCHAR pDllPath, ULONG uFlag, PUNICODE_STRING pString, PHANDLE pHandle) {
PPARAM_DATA data = (PPARAM_DATA)0x1234567890;
//修复
UINT64 uFixAddr = (UINT64)data->fnLdrLoadDll;
for (int n = 0; n < sizeof(JMP_PATCH); n++) {
*(byte*)(uFixAddr + n) = data->szBackupCode[n];
}
//加载DLL
data->fnRtlInitUnicodeString(&data->UnicodeString, data->DllName);
data->fnLdrLoadDll(data->DllPath, data->Flags, &data->UnicodeString, &data->ModuleHandle);
return data->fnLdrLoadDll(pDllPath,uFlag,pString,pHandle);
}
DWORD WINAPI MyLdrLoadDllEnd()
{
return 0;
}
UINT64 GetRemoteNtdllImagebase(HANDLE hGameHandle, UINT64 uCheckTargetFuncAddr,UINT64 uOffset) {
UINT64 uAddr = 0x10000;
MEMORY_BASIC_INFORMATION Mbi;
while (uAddr < 0x8000000000000) {
if (VirtualQueryEx(hGameHandle, (PVOID)uAddr, &Mbi, sizeof(MEMORY_BASIC_INFORMATION)) == sizeof(MEMORY_BASIC_INFORMATION)) {
if ((Mbi.RegionSize == 0x1000) && (Mbi.Protect == PAGE_READONLY)) {
IMAGE_DOS_HEADER ImageDosHeader = { 0 };
SIZE_T Lp = 0;
if (ReadProcessMemory(hGameHandle, (PVOID)Mbi.BaseAddress, &ImageDosHeader, sizeof(IMAGE_DOS_HEADER), &Lp)) {
if (ImageDosHeader.e_magic == IMAGE_DOS_SIGNATURE) {
IMAGE_NT_HEADERS ImageNtHeader = { 0 };
if (ReadProcessMemory(hGameHandle, (PVOID)((UINT64)Mbi.BaseAddress + ImageDosHeader.e_lfanew), &ImageNtHeader, sizeof(IMAGE_NT_HEADERS), &Lp)) {
if (ImageNtHeader.Signature == IMAGE_NT_SIGNATURE) {
WORD wCmpByte = 0;
if (ReadProcessMemory(hGameHandle, (PVOID)((UINT64)Mbi.BaseAddress + uOffset), &wCmpByte, sizeof(WORD), &Lp)) {
if (wCmpByte == *(WORD*)uCheckTargetFuncAddr) {
return (UINT64)Mbi.BaseAddress;
}
}
}
}
}
}
}
uAddr += Mbi.RegionSize;
}
else {
break;
}
}
return 0;
}
void InstallShellCode(HANDLE hGameHandle, LPCWSTR lpcwDllPath) {
HMODULE hNtDLL = GetModuleHandle("ntdll.dll");
if (hNtDLL) {
//计算偏移
UINT64 uFuncAddr = (UINT64)GetProcAddress(hNtDLL, "LdrLoadDll");
UINT64 uOffset = uFuncAddr - (UINT64)hNtDLL;
/*
进程直接挂起无法获取到快照表,只能使用内存枚举,然后直接特征码比对
*/
UINT64 uTargetNtdllBase = GetRemoteNtdllImagebase(hGameHandle, uFuncAddr, uOffset);
//找到目标NTDLL的基址了
if (uTargetNtdllBase != 0) {
//初始化shellcode使用的参数数据结构
PARAM_DATA data = { 0 };
data.fnRtlInitUnicodeString = (pRtlInitUnicodeString)(uTargetNtdllBase + ((UINT64)GetProcAddress(hNtDLL, "RtlInitUnicodeString") - (UINT64)hNtDLL));
data.fnLdrLoadDll = (pLdrLoadDll)(uTargetNtdllBase + uOffset);
memcpy(data.DllName, lpcwDllPath, (wcslen(lpcwDllPath) + 1)*sizeof(WCHAR));
data.DllPath = NULL;
data.Flags = 0;
data.ModuleHandle = INVALID_HANDLE_VALUE;
//备份恢复代码
if (ReadProcessMemory(hGameHandle, (PVOID)(uTargetNtdllBase + uOffset), &data.szBackupCode, sizeof(JMP_PATCH) + 3, NULL)) {
printf("Save BackupCode Success!\r\n");
}
//存放数据
PVOID pDataAdr = VirtualAllocEx(hGameHandle, NULL, sizeof(PARAM_DATA), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pDataAdr) {
//存放代码
UINT64 SizeOfCode = (UINT64)MyLdrLoadDllEnd - (UINT64)MyLdrLoadDll; //计算长度
PVOID pCode = VirtualAllocEx(hGameHandle, NULL, SizeOfCode, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (pCode) {
BYTE *pCache = new byte[SizeOfCode];
if (pCache) {
//代码拷出来
memcpy(pCache, &MyLdrLoadDll, SizeOfCode);
//修正shellcode参数地址
for (DWORD i = 0; i < SizeOfCode; i++) {
if (*(UINT64*)((UINT64)pCache + i) == 0x1234567890) {
*(UINT64*)((UINT64)pCache + i) = (UINT64)pDataAdr;
break;
}
}
//写入参数
if (WriteProcessMemory(hGameHandle, pDataAdr, &data, sizeof(PARAM_DATA), NULL)) {
printf("Write ParamData Success! [%p]\r\n", pDataAdr);
}
//写入shellcode
if (WriteProcessMemory(hGameHandle, pCode, pCache, SizeOfCode, NULL)) {
printf("Write ShellCode Success! [%p]\r\n", pCode);
}
//HOOK 目标API
DWORD oldProtect = 0;
if (VirtualProtectEx(hGameHandle, (PVOID)(uTargetNtdllBase + uOffset), sizeof(JMP_PATCH), PAGE_EXECUTE_READWRITE, &oldProtect) == TRUE) {
JMP_PATCH JmpPatch = { 0 };
JmpPatch.REax = 0xB848;
JmpPatch.JMP = 0xE0FF;
JmpPatch.uAddress = (UINT64)pCode;
if (WriteProcessMemory(hGameHandle, (PVOID)(uTargetNtdllBase + uOffset) , &JmpPatch, sizeof(JMP_PATCH), NULL)) {
printf("Write Patch Success! [0x%llX]\r\n", uTargetNtdllBase + uOffset );
}
}
}
}
}
}
}
}
int main(int argc, char *argv[]){
printf("Shellcode Inject Tools Build 20230718\r\n");
if (argc > 1) {
char szBin[MAX_PATH] = { 0 };
sprintf_s(szBin,"%s -launch", argv[1]);
printf("Launch Command: %s\r\n" , szBin);
char szInjectModulePath[MAX_PATH] = { 0 };
GetCurrentDirectory(MAX_PATH, szInjectModulePath);
strcat_s(szInjectModulePath, DEF_INJECT_MODULE);
printf("Inject Module Path:%s\r\n", szInjectModulePath);
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
if (CreateProcess(NULL, szBin, NULL, NULL,FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
printf("Game Launch Pid:%d ...\r\n", pi.dwProcessId);
WCHAR wLoadFile[MAX_PATH * 2] = { 0 };
if (MultiByteToWideChar(CP_ACP, 0, szInjectModulePath, strlen(szInjectModulePath), wLoadFile, MAX_PATH * 2) > 0) {
//安装shellcode
InstallShellCode(pi.hProcess, wLoadFile);
}
ResumeThread(pi.hThread);
printf("Game Start...");
Sleep(3 * 1000);
}
}else {
printf("Params Wrong!Need game bin path\r\n");
system("pause");
}
return 0;
}