program ThreadExitHook;
{$APPTYPE CONSOLE}
uses
Windows,
Classes,
madCodeHook;
type
TLdrShutdownThread = procedure; stdcall;
var
LdrShutdownThreadNext : TLdrShutdownThread;
procedure LdrShutdownThreadCallback; stdcall;
begin
WriteLn('Thread terminating:', GetCurrentThreadId);
LdrShutdownThreadNext;
end;
begin
HookAPI('ntdll.dll', 'LdrShutdownThread', @LdrShutdownThreadCallback, @LdrShutdownThreadNext);
TThread.CreateAnonymousThread(procedure begin
WriteLn('Hello from Thread');
Sleep(1000);
end).Start;
ReadLn;
UnhookAPI(@LdrShutdownThreadNext);
end.
Вот версия, которая не зависит от какой-либо внешней библиотеки:
program Project7;
{$APPTYPE CONSOLE}
uses
Windows,
Classes;
{==============================================================================}
function IsWin9x: Boolean;
asm
MOV EAX, FS:[030H]
TEST EAX, EAX
SETS AL
end;
{------------------------------------------------------------------------------}
function CalcJump(Src, Dest: DWORD): DWORD;
begin
if (Dest < Src) then begin
Result := Src - Dest;
Result := $FFFFFFFF - Result;
Result := Result - 4;
end else begin
Result := Dest - Src;
Result := Result - 5;
end;
end;
{------------------------------------------------------------------------------}
function OpCodeLength(Address: DWORD): DWORD; cdecl; assembler;
const
O_UNIQUE = 0;
O_PREFIX = 1;
O_IMM8 = 2;
O_IMM16 = 3;
O_IMM24 = 4;
O_IMM32 = 5;
O_IMM48 = 6;
O_MODRM = 7;
O_MODRM8 = 8;
O_MODRM32 = 9;
O_EXTENDED = 10;
O_WEIRD = 11;
O_ERROR = 12;
asm
pushad
cld
xor edx, edx
mov esi, Address
mov ebp, esp
push 1097F71Ch
push 0F71C6780h
push 17389718h
push 101CB718h
push 17302C17h
push 18173017h
push 0F715F547h
push 4C103748h
push 272CE7F7h
push 0F7AC6087h
push 1C121C52h
push 7C10871Ch
push 201C701Ch
push 4767602Bh
push 20211011h
push 40121625h
push 82872022h
push 47201220h
push 13101419h
push 18271013h
push 28858260h
push 15124045h
push 5016A0C7h
push 28191812h
push 0F2401812h
push 19154127h
push 50F0F011h
mov ecx, 15124710h
push ecx
push 11151247h
push 10111512h
push 47101115h
mov eax, 12472015h
push eax
push eax
push 12471A10h
add cl, 10h
push ecx
sub cl, 20h
push ecx
xor ecx, ecx
dec ecx
@@ps:
inc ecx
mov edi, esp
@@go:
lodsb
mov bh, al
@@ft:
mov ah, [edi]
inc edi
shr ah, 4
sub al, ah
jnc @@ft
mov al, [edi-1]
and al, 0Fh
cmp al, O_ERROR
jnz @@i7
pop edx
not edx
@@i7:
inc edx
cmp al, O_UNIQUE
jz @@t_exit
cmp al, O_PREFIX
jz @@ps
add edi, 51h
cmp al, O_EXTENDED
jz @@go
mov edi, [ebp+((1+8)*4)+4]
@@i6:
inc edx
cmp al, O_IMM8
jz @@t_exit
cmp al, O_MODRM
jz @@t_modrm
cmp al, O_WEIRD
jz @@t_weird
@@i5:
inc edx
cmp al, O_IMM16
jz @@t_exit
cmp al, O_MODRM8
jz @@t_modrm
@@i4:
inc edx
cmp al, O_IMM24
jz @@t_exit
@@i3:
inc edx
@@i2:
inc edx
pushad
mov al, 66h
repnz scasb
popad
jnz @@c32
@@d2:
dec edx
dec edx
@@c32:
cmp al, O_MODRM32
jz @@t_modrm
sub al, O_IMM32
jz @@t_imm32
@@i1:
inc edx
@@t_exit:
jmp @@ASMEnded
@@t_modrm:
lodsb
mov ah, al
shr al, 7
jb @@prmk
jz @@prm
add dl, 4
pushad
mov al, 67h
repnz scasb
popad
jnz @@prm
@@d3: sub dl, 3
dec al
@@prmk:jnz @@t_exit
inc edx
inc eax
@@prm:
and ah, 00000111b
pushad
mov al, 67h
repnz scasb
popad
jz @@prm67chk
cmp ah, 04h
jz @@prmsib
cmp ah, 05h
jnz @@t_exit
@@prm5chk:
dec al
jz @@t_exit
@@i42: add dl, 4
jmp @@t_exit
@@prm67chk:
cmp ax, 0600h
jnz @@t_exit
inc edx
jmp @@i1
@@prmsib:
cmp al, 00h
jnz @@i1
lodsb
and al, 00000111b
sub al, 05h
jnz @@i1
inc edx
jmp @@i42
@@t_weird:
test byte ptr [esi], 00111000b
jnz @@t_modrm
mov al, O_MODRM8
shr bh, 1
adc al, 0
jmp @@i5
@@t_imm32:
sub bh, 0A0h
cmp bh, 04h
jae @@d2
pushad
mov al, 67h
repnz scasb
popad
jnz @@chk66t
@@d4: dec edx
dec edx
@@chk66t:
pushad
mov al, 66h
repnz scasb
popad
jz @@i1
jnz @@d2
@@ASMEnded:
mov esp, ebp
mov [result+(9*4)], edx
popad
end;
{------------------------------------------------------------------------------}
function ApiHook(ModName, ApiName: PChar; FuncAddr, HookedApi: Pointer; var MainApi: Pointer): Boolean;
var
dwCount, Cnt, i, jmp: DWORD;
P: Pointer;
hMod, OldP, TMP: Cardinal;
begin
Result := False;
if IsWin9x then
Exit;
P := FuncAddr;
if P = nil then begin
hMod := GetModuleHandle(ModName);
if hMod = 0 then
hMod := LoadLibrary(ModName);
P := GetProcAddress(hMod, ApiName);
end;
if (P = nil) or (HookedApi = nil) then
Exit;
if not VirtualProtect(P, $40, PAGE_EXECUTE_READWRITE, @OldP) then
Exit;
if ((Byte(P^) = $68) and (DWORD(Pointer(DWORD(P) + 1)^) = DWORD(HookedApi))) then
Exit;
MainApi := VirtualAlloc(nil, $1000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if MainApi = nil then
Exit;
Cnt := 0;
for dwCount := 0 to $3F do begin
Inc(Cnt, OpCodeLength(DWORD(P) + Cnt));
for i := 0 to Cnt - 1 do
PByte(MainApi)[i] := PByte(P)[i];
if Cnt > 5 then
Break;
end;
PByte(MainApi)[Cnt] := $68;
DWORD(Pointer(DWORD(MainApi) + Cnt + 1)^) := DWORD(P) + Cnt;
PByte(MainApi)[Cnt + 5] := $C3;
PByte(MainApi)[Cnt + 6] := $99;
if (OpCodeLength(DWORD(MainApi)) = 5) and
((Byte(MainApi^) = $E8) or (Byte(MainApi^) = $E9)) then
begin
jmp := DWORD(P) + DWORD(Pointer(DWORD(MainApi) + 1)^) + 5;
DWORD(Pointer(DWORD(MainApi) + 1)^) := CalcJump(DWORD(MainApi), jmp);
end;
PByte(P)[0] := $68;
DWORD(Pointer(DWORD(P) + 1)^) := DWORD(HookedApi);
PByte(P)[5] := $C3;
VirtualProtect(P, $40, OldP, @TMP);
Result := True;
end;
{------------------------------------------------------------------------------}
function ApiUnHook(ModName, ApiName: PChar; FuncAddr, HookedApi: Pointer; var MainApi: Pointer): Boolean;
var
dwCount, Cnt, i, jmp: DWORD;
P: Pointer;
hMod, OldP, TMP: Cardinal;
begin
Result := False;
if IsWin9x then
Exit;
P := FuncAddr;
if P = nil then begin
hMod := GetModuleHandle(ModName);
P := GetProcAddress(hMod, ApiName);
end;
if (P = nil) or (MainApi = nil) or (HookedApi = nil) then
Exit;
if not VirtualProtect(P, $40, PAGE_EXECUTE_READWRITE, @OldP) then
Exit;
if ((Byte(P^) <> $68) or (DWORD(Pointer(DWORD(P) + 1)^) <> DWORD(HookedApi))) then
Exit;
Cnt := 0;
for dwCount := 0 to $3F do begin
Inc(Cnt, OpCodeLength(DWORD(MainApi) + Cnt));
if (Byte(Pointer(DWORD(MainApi) + Cnt)^) = $C3) and
(Byte(Pointer(DWORD(MainApi) + Cnt + 1)^) = $99) then
Break;
for i := 0 to Cnt - 1 do
PByte(P)[i] := PByte(MainApi)[i];
end;
if (OpCodeLength(DWORD(P)) = 5) and ((Byte(P^) = $E8) or (byte(P^) = $E9)) then begin
jmp := DWORD(MainApi) + DWORD(Pointer(DWORD(MainApi) + 1)^) + 5;
DWORD(Pointer(DWORD(P) + 1)^) := CalcJump(DWORD(P), jmp);
end;
VirtualProtect(P, $40, OldP, @TMP);
VirtualFree(MainApi, 0, MEM_RELEASE);
Result := True;
end;
{==============================================================================}
type
TLdrShutdownThread = procedure; stdcall;
var
LdrShutdownThreadNext : TLdrShutdownThread;
procedure LdrShutdownThreadCallback; stdcall;
begin
WriteLn('Thread terminating:', GetCurrentThreadId);
LdrShutdownThreadNext;
end;
begin
ApiHook('ntdll.dll', 'LdrShutdownThread', nil, @LdrShutdownThreadCallback, @LdrShutdownThreadNext);
TThread.CreateAnonymousThread(procedure begin
WriteLn('Hello from Thread');
Sleep(1000);
WriteLn('Waking up');
end).Start;
ReadLn;
ApiUnHook('ntdll.dll', 'LdrShutdownThread', nil, @LdrShutdownThreadCallback, @LdrShutdownThreadNext);
TThread.CreateAnonymousThread(procedure begin
WriteLn('Hello from Thread');
Sleep(1000);
WriteLn('Waking up');
end).Start;
ReadLn;
end.