Мне необходимо заинжектить свою Dll (64 бита) в 64-битный процесс. Проблема в том, что выложенный код отлично работает в связке 32bit Injector + 32bit Dll + 32bit Targer processs, а при перекомпиляции всех участников в 64bit Injector + 64bit Dll + 64bit Targer processs, при выгрузке Dll в Target process Access Violation $C0000005. Подскажите в чем может быть дело.
Код инжектора:
function SetDebugPriv: Boolean;
var
Token: THandle;
tkp: TTokenPrivileges;
ReturnLength: DWORD;
begin
Result := false;
// Получаем токен текущего процесса
if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token) then
try
// Получаем Luid привилегии
if LookupPrivilegeValue(nil, PChar('SeDebugPrivilege'), tkp.Privileges[0].Luid) then
begin
// Заполняем необходимые параметры
tkp.PrivilegeCount := 1;
tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
// Включаем привилегию
Result := AdjustTokenPrivileges(Token, false, tkp, 0, nil, ReturnLength);
end;
finally
CloseHandle(Token);
end;
end;
function TForm22.InjectLib(ProcessID: Integer): Boolean;
var
Process: HWND;
ThreadRtn: FARPROC;
DllPath: AnsiString;
RemoteDll: Pointer;
BytesWriten: SIZE_T;
Thread: DWORD;
ThreadId: DWORD;
begin
// Устанавливаем отладочные привилегии для нашего процесса
Result := SetDebugPriv;
if not Result then Exit;
// Открываем процесс
Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
PROCESS_VM_WRITE, True, ProcessID);
if Process = 0 then Exit;
try
// Выделяем в нем память под строку
DllPath := AnsiString({ExtractFilePath(ParamStr(0)) +} DLLName) + #0;
RemoteDll := VirtualAllocEx(Process, nil, Length(DllPath),
MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
if RemoteDll = nil then Exit;
try
// Пишем путь к длл в его адресное пространство
if not WriteProcessMemory(Process, RemoteDll, @DllPath[1],
Length(DllPath), BytesWriten) then Exit;
if BytesWriten <> DWORD(Length(DllPath)) then Exit;
// Получаем адрес функции из Kernel32.dll
ThreadRtn := GetProcAddress(GetModuleHandle('Kernel32.dll'), 'LoadLibraryA');
if ThreadRtn = nil then Exit;
// Запускаем удаленный поток
Thread := CreateRemoteThread(Process, nil, 0, ThreadRtn, RemoteDll, 0, ThreadId);
if Thread = 0 then Exit;
try
// Ждем пока удаленный поток отработает...
Result := WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0;
finally
CloseHandle(Thread);
end;
finally
VirtualFreeEx(Process, RemoteDll, 0, MEM_RELEASE);
end;
finally
CloseHandle(Process);
end;
end;
// Данная функция запускает в удаленном процессе поток
// который стартует с инструкции JMP [EBX]
// В EBX будет лежать адрес функции SelfUnload,
// который будет выгружать библиотеку.
// Адрес функции рассчитывается отдельно и равен
// адресу загрузки библиотеки + смещение на саму функцию
// =============================================================================
function TForm22.EjectLib(ProcessID: Integer): Boolean;
var
hLibHandle: THandle;
hModuleSnap: THandle;
ModuleEntry: TModuleEntry32;
OpCodeData: Word;
Process: HWND;
BytesWriten: SIZE_T;
Thread: DWORD;
ThreadId: DWORD;
ExitCode: DWORD;
PLibHandle: PDWORD;
OpCode: PWORD;
CurrUnloadAddrOffset: DWORD;
UnloadAddrOffset: DWORD;
begin
// Устанавливаем отладочные привилегии для нашего процесса
Result := SetDebugPriv;
if not Result then Exit;
// рассчитываем оффсет адреса выгрузки библиотеки относительно адреса ее загрузки
hLibHandle := LoadLibrary(PChar(DLLName));
try
UnloadAddrOffset :=
DWORD(GetProcAddress(hLibHandle, 'SelfUnload')) - hLibHandle;
if UnloadAddrOffset = -hLibHandle then Exit;
finally
FreeLibrary(hLibHandle);
end;
// Находим адрес библиотеки в чужом адресном пространстве
hModuleSnap := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessID);
if hModuleSnap <> INVALID_HANDLE_VALUE then
try
FillChar(ModuleEntry, SizeOf(TModuleEntry32), #0);
ModuleEntry.dwSize := SizeOf(TModuleEntry32);
if not Module32First(hModuleSnap, ModuleEntry) then Exit;
repeat
if AnsiUpperCase(ModuleEntry.szModule) =
AnsiUpperCase(ExtractFileName(DLLName)) then
begin
// Получаем адрес функции выгрузки
CurrUnloadAddrOffset := ModuleEntry.hModule + UnloadAddrOffset;
Break;
end;
until not Module32Next(hModuleSnap, ModuleEntry);
finally
CloseHandle(hModuleSnap);
end;
if CurrUnloadAddrOffset = 0 then
begin
lbStatus.Items.Add('Library has not injected.');
Exit;
end;
// Открываем процесс
Process := OpenProcess(PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or
PROCESS_VM_WRITE, True, ProcessID);
if Process = 0 then Exit;
try
// Пишем опкод jmp [ebx]
OpCode := VirtualAllocEx(Process, nil, 2,
MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
if OpCode = nil then Exit;
try
OpCodeData := $23FF;
if not WriteProcessMemory(Process, OpCode, @OpCodeData,
2, BytesWriten) then Exit;
// Пишем адрес функции выгрузки (он будет лежать в EBX при старте потока)
PLibHandle := VirtualAllocEx(Process, nil, 4,
MEM_COMMIT or MEM_TOP_DOWN, PAGE_READWRITE);
if PLibHandle = nil then Exit;
try
if not WriteProcessMemory(Process, PLibHandle, @CurrUnloadAddrOffset,
4, BytesWriten) then Exit;
// запускаем поток
Thread := CreateRemoteThread(Process, nil, 0, OpCode,
PLibHandle, 0, ThreadId);
if Thread = 0 then Exit;
try
// Ждем пока удаленный поток отработает...
if (WaitForSingleObject(Thread, INFINITE) = WAIT_OBJECT_0) then
if GetExitCodeThread(Thread, ExitCode) then
Result := ExitCode = 0;
finally
CloseHandle(Thread);
end;
finally
VirtualFreeEx(Process, PLibHandle, 0, MEM_RELEASE);
end;
finally
VirtualFreeEx(Process, OpCode, 0, MEM_RELEASE);
end;
finally
CloseHandle(Process);
end;
end;
Код Dll:
procedure DLLEntryPoint(dwReason: DWORD);
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
MessageBoxA(0, 'Injected', 'Injected', MB_OK);
end;
DLL_PROCESS_DETACH:
begin
MessageBoxA(0, 'Rejected', 'Rejected', MB_OK);
end;
end;
end;
procedure SelfUnload(lpParametr: Pointer); stdcall;
begin
FreeLibraryAndExitThread(HInstance, 0);
end;
exports
SelfUnload;
begin
DLLProc := @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.