cnhup / delphi-detours-library

Automatically exported from code.google.com/p/delphi-detours-library
0 stars 0 forks source link

LdrShutdownThreadCallback #13

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hello!

Can you do a demo how to hook this function? I would like to hook thread 
creation/termination in only my app. Is good idea for your demo. :)

Original issue reported on code.google.com by david.lo...@gmail.com on 9 Jan 2015 at 11:01

GoogleCodeExporter commented 9 years ago
Hi,
Here is a quick example:

//------------------------------------
program HookThread;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils, System.Classes,
  CPUID in 'E:\Delphi\DDL\trunk\v2\src\CPUID.pas',
  DDetours in 'E:\Delphi\DDL\trunk\v2\src\DDetours.pas',
  InstDecode in 'E:\Delphi\DDL\trunk\v2\src\InstDecode.pas';

type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  TrampoBeginThread: function(SecurityAttributes: Pointer; StackSize: LongWord; ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord;
    var ThreadId: TThreadID): THandle;
  TrampoTerminate: procedure(Self: Pointer);
  m: TMyThread;

procedure TerminateHooked(Self: Pointer);
begin
  Writeln(Format('%s Terminated!', [TThread(Self).ClassName]));
  TrampoTerminate(Self);
end;

function BeginThreadHooked(SecurityAttributes: Pointer; StackSize: LongWord; 
ThreadFunc: TThreadFunc; Parameter: Pointer; CreationFlags: LongWord;
  var ThreadId: TThreadID): THandle;
begin
  Writeln(Format('%s Created!', [TThread(Parameter).ClassName]));
  Result := TrampoBeginThread(SecurityAttributes, StackSize, ThreadFunc, Parameter, CreationFlags, ThreadId);
end;

{ TMyThread }

procedure TMyThread.Execute;
begin
  inherited;

end;

begin
  { initialization }

  @TrampoBeginThread := InterceptCreate(@BeginThread, @BeginThreadHooked);
  @TrampoTerminate := InterceptCreate(@TThread.Terminate, @TerminateHooked);

  m := TMyThread.Create(False);
  sleep(1000);
  m.Terminate;
  m.Free;

  { finalization }

  InterceptRemove(@TrampoBeginThread);
  InterceptRemove(@TrampoTerminate);

  Readln;

end.
//----------------------------

I am not sure that i will integrate this example in the DDL demo .
The purpose of demo is only to show how the library works ! and there is 
already many integrated simple demo.

Regards,
Mahdi

Original comment by ismspi...@gmail.com on 9 Jan 2015 at 4:29

GoogleCodeExporter commented 9 years ago
Hello!

This is a better way to do it however I am not sure if this will work on 
XP/XP64..

- LdrShutdownThread ( Shutdown )
- BaseThreadInitThunk ( Initialize )
- RtlUserThreadStart ( Start )

Original comment by david.lo...@gmail.com on 9 Jan 2015 at 4:36

Attachments:

GoogleCodeExporter commented 9 years ago
Its seems this library doesn't allow hooking in this way :/

Original comment by david.lo...@gmail.com on 9 Jan 2015 at 4:52

GoogleCodeExporter commented 9 years ago
Same example could be used with DDL:
//------------------------------------
program HookThread;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils, WinApi.Windows, System.Classes,
  CPUID in 'E:\Delphi\DDL\trunk\v2\src\CPUID.pas',
  DDetours in 'E:\Delphi\DDL\trunk\v2\src\DDetours.pas',
  InstDecode in 'E:\Delphi\DDL\trunk\v2\src\InstDecode.pas';

type
  LPTHREAD_START_ROUTINE = function(lpThreadParameter: LPVOID): DWORD; stdcall;
  TLdrShutdownThread = procedure; stdcall;
  TRtlUserThreadStart = procedure(pfnStartAddr: LPTHREAD_START_ROUTINE; pvParam: PVOID); stdcall;

var
  LdrShutdownThreadNext: TLdrShutdownThread;
  RtlUserThreadStartNext: TRtlUserThreadStart;
  RunningThreads: Integer = 0;

procedure LdrShutdownThreadCallback;
begin
  Writeln('Shutdown Thread !');
  LdrShutdownThreadNext;
end;

procedure RtlUserThreadStartCallback(pfnStartAddr: LPTHREAD_START_ROUTINE; 
pvParam: PVOID);
begin
  Writeln('Thread Started !');
  RtlUserThreadStartNext(pfnStartAddr, pvParam);
end;

type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

  { TMyThread }

procedure TMyThread.Execute;
begin
  inherited;

end;

var
  m: TMyThread;

begin

  @LdrShutdownThreadNext := InterceptCreate('ntdll.dll', 'LdrShutdownThread', @LdrShutdownThreadCallback);
  @RtlUserThreadStartNext := InterceptCreate('ntdll.dll', 'RtlUserThreadStart', @RtlUserThreadStartCallback);
  m := TMyThread.Create(False);
  Sleep(1000);
  m.Terminate;
  m.Free;
  InterceptRemove(@LdrShutdownThreadNext);
  InterceptRemove(@RtlUserThreadStartNext);
  ReadLn;

end.
//------------------------------

Original comment by ismspi...@gmail.com on 9 Jan 2015 at 4:58

GoogleCodeExporter commented 9 years ago
Seems LdrShutdownThread is not getting hooked on XE7 :/

But the other hook work!

Original comment by david.lo...@gmail.com on 9 Jan 2015 at 5:04

GoogleCodeExporter commented 9 years ago
I tested on win7 with XE7 and it's work!

Original comment by ismspi...@gmail.com on 9 Jan 2015 at 5:17

GoogleCodeExporter commented 9 years ago
Yes it seems I removed the hook too fast :D

Original comment by david.lo...@gmail.com on 9 Jan 2015 at 5:20

GoogleCodeExporter commented 9 years ago
Btw this fails on x64!

  @CreateThread := InterceptCreate('kernel32.dll', 'CreateThread', @CreateThreadCallback);

Original comment by david.lo...@gmail.com on 9 Jan 2015 at 9:41

GoogleCodeExporter commented 9 years ago
Please report the new one in a new issue (including a steps to produce the 
issue).

Original comment by ismspi...@gmail.com on 9 Jan 2015 at 10:50

GoogleCodeExporter commented 9 years ago

Original comment by ismspi...@gmail.com on 9 Jan 2015 at 11:24

GoogleCodeExporter commented 9 years ago
There seems to be another bug with BaseThreadInitThunk. Hook fails with 32 bit! 
But work with x64 :/

program HookThread;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  WinApi.Windows,
  System.Classes,
  CPUID,
  DDetours,
  InstDecode;

type
  LPTHREAD_START_ROUTINE = function(lpThreadParameter: LPVOID): DWORD; stdcall;
  TLdrShutdownThread = procedure; stdcall;

  TRtlUserThreadStart = procedure(lpStartAddress: LPTHREAD_START_ROUTINE; lpParameter: PVOID); stdcall;
  TBaseThreadInitThunk = procedure(LdrReserved: DWORD; lpStartAddress: LPTHREAD_START_ROUTINE; lpParameter: LPVOID); register;

  TCreateThread = function(lpThreadAttributes: Pointer; dwStackSize: SIZE_T; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer; dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle; stdcall;

var
  LdrShutdownThread: TLdrShutdownThread;
  RtlUserThreadStart: TRtlUserThreadStart;
  BaseThreadInitThunk: TBaseThreadInitThunk;
  CreateThread: TCreateThread;

procedure LdrShutdownThreadCallback; stdcall;
begin
  Writeln('Thread Destroyed: ' + GetCurrentThreadId.ToString);
  LdrShutdownThread;
end;

procedure RtlUserThreadStartCallback(lpStartAddress: LPTHREAD_START_ROUTINE; 
lpParameter: PVOID); stdcall;
begin
  Writeln('Thread Started: ' + GetCurrentThreadId.ToString);
  RtlUserThreadStart(lpStartAddress, lpParameter);
end;

procedure BaseThreadInitThunkCallback(LdrReserved: DWORD; lpStartAddress: 
LPTHREAD_START_ROUTINE; lpParameter: LPVOID); register;
begin
  Writeln('Thread Started: ' + GetCurrentThreadId.ToString);
  BaseThreadInitThunk(LdrReserved, lpStartAddress, lpParameter);
end;

function CreateThreadCallback(lpThreadAttributes: Pointer; dwStackSize: SIZE_T; 
lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer; dwCreationFlags: 
DWORD; var lpThreadId: DWORD): THandle; stdcall;
begin
  Result := CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
  Writeln('Thread Created: ' + lpThreadId.ToString + ' with Handle: ' + Result.ToString);
end;

begin
  @BaseThreadInitThunk := InterceptCreate('kernel32.dll', 'BaseThreadInitThunk', @BaseThreadInitThunkCallback);
  @LdrShutdownThread := InterceptCreate('ntdll.dll', 'LdrShutdownThread', @LdrShutdownThreadCallback);
  @RtlUserThreadStart := InterceptCreate('ntdll.dll', 'RtlUserThreadStart', @RtlUserThreadStartCallback);
  @CreateThread := InterceptCreate('kernel32.dll', 'CreateThread', @CreateThreadCallback);

  TThread.CreateAnonymousThread(
  procedure
  begin
    Sleep(1000);
  end).Start;

  ReadLn;
  InterceptRemove(@LdrShutdownThread);
  InterceptRemove(@BaseThreadInitThunk);
  InterceptRemove(@RtlUserThreadStart);
  InterceptRemove(@CreateThread);
end.

Original comment by david.lo...@gmail.com on 10 Jan 2015 at 10:26

GoogleCodeExporter commented 9 years ago
Hi,
This is not a bug related to DDL!
First you are hooking undocumented functions.
Second TRtlUserThreadStart seems to be register and TBaseThreadInitThunk seems 
to be stdcall.
DDL will fails when passing wrong params or wrong calling convention (since 
it's undocumented functions , it's hardly to guess the correct args 
type/calling convention.
Last thing, when you report a bug make sure that you are given a correct 
functions parameters and calling convention so i can work on your 
issue.Undocumented functions are hardly to debug and hardly for invoke (I don't 
guarantee anything!).

//---------------------------------------------
program Project1;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  WinApi.Windows,
  System.Classes,
  CPUID in 'E:\Delphi\DDL\trunk\v2\src\CPUID.pas',
  DDetours in 'E:\Delphi\DDL\trunk\v2\src\DDetours.pas',
  InstDecode in 'E:\Delphi\DDL\trunk\v2\src\InstDecode.pas';

type
  LPTHREAD_START_ROUTINE = function(lpThreadParameter: LPVOID): DWORD; stdcall;
  TLdrShutdownThread = procedure; stdcall;

  TRtlUserThreadStart = procedure(lpStartAddress: LPTHREAD_START_ROUTINE; lpParameter: PVOID); register;
  TBaseThreadInitThunk = procedure(LdrReserved: DWORD; lpStartAddress: LPTHREAD_START_ROUTINE; lpParameter: LPVOID); stdcall;

  TCreateThread = function(lpThreadAttributes: Pointer; dwStackSize: SIZE_T; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer;
    dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle; stdcall;

var
  LdrShutdownThread: TLdrShutdownThread;
  RtlUserThreadStart: TRtlUserThreadStart;
  BaseThreadInitThunk: TBaseThreadInitThunk;
  CreateThread: TCreateThread;

procedure LdrShutdownThreadCallback; stdcall;
begin
  Writeln('Thread Destroyed: ' + GetCurrentThreadId.ToString);
  LdrShutdownThread;
end;

procedure RtlUserThreadStartCallback(lpStartAddress: LPTHREAD_START_ROUTINE; 
lpParameter: PVOID); register;
begin
  Writeln('Thread Started: ' + GetCurrentThreadId.ToString);
  RtlUserThreadStart(lpStartAddress, lpParameter);
end;

procedure BaseThreadInitThunkCallback(LdrReserved: DWORD; lpStartAddress: 
LPTHREAD_START_ROUTINE; lpParameter: LPVOID); stdcall;
begin
  // Writeln('Thread Started: ' + GetCurrentThreadId.ToString);
  BaseThreadInitThunk(LdrReserved, lpStartAddress, lpParameter);
end;

function CreateThreadCallback(lpThreadAttributes: Pointer; dwStackSize: SIZE_T; 
lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer;
  dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle; stdcall;
begin
  Result := CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
  Writeln('Thread Created: ' + lpThreadId.ToString + ' with Handle: ' + Result.ToString);
end;

begin
  @BaseThreadInitThunk := InterceptCreate('kernel32.dll', 'BaseThreadInitThunk', @BaseThreadInitThunkCallback);
  @LdrShutdownThread := InterceptCreate('ntdll.dll', 'LdrShutdownThread', @LdrShutdownThreadCallback);
  @RtlUserThreadStart := InterceptCreate('ntdll.dll', 'RtlUserThreadStart', @RtlUserThreadStartCallback);
  @CreateThread := InterceptCreate('kernel32.dll', 'CreateThread', @CreateThreadCallback);

  TThread.CreateAnonymousThread(
    procedure
    begin
      Sleep(1000);
    end).Start;

  ReadLn;
  InterceptRemove(@LdrShutdownThread);
  InterceptRemove(@BaseThreadInitThunk);
  InterceptRemove(@RtlUserThreadStart);
  InterceptRemove(@CreateThread);

end.

Original comment by ismspi...@gmail.com on 11 Jan 2015 at 11:14

GoogleCodeExporter commented 9 years ago
Yes I use these hooked functions for thread diagnostics! To find bugs in my 
program :)

Original comment by david.lo...@gmail.com on 11 Jan 2015 at 11:25