Questions about DLL Injection

c++ / delphi package - dll injection and api hooking
Pacino
Posts: 8
Joined: Thu May 05, 2005 3:17 pm

Questions about DLL Injection

Post by Pacino »

Can I use MadCodeHook to inject a specified DLL into a desired process (for example, target.exe) and achieve the following goal:
Add menu item to the popupmenu of target process and implement onclick event?

Thank you very much.
dcsoft
Posts: 380
Joined: Sat Dec 11, 2004 2:11 am
Location: San Francisco Bay Area, CA USA
Contact:

Re: Questions about DLL Injection

Post by dcsoft »

Pacino wrote:Can I use MadCodeHook to inject a specified DLL into a desired process (for example, target.exe) and achieve the following goal:
Add menu item to the popupmenu of target process and implement onclick event?
Yes, you can. Call madCodeHook's InjectLibrary() to inject your DLL into the target process. Then in the DllMain() of your DLL, call the Windows API GetMenu(hwnd) where hwnd is the frame window of the target.exe.

You can manipulate the menu bar from the returned HMENU.

Cheers,
David
Pacino
Posts: 8
Joined: Thu May 05, 2005 3:17 pm

Re: Questions about DLL Injection

Post by Pacino »

dcsoft wrote:
Pacino wrote:Can I use MadCodeHook to inject a specified DLL into a desired process (for example, target.exe) and achieve the following goal:
Add menu item to the popupmenu of target process and implement onclick event?
Yes, you can. Call madCodeHook's InjectLibrary() to inject your DLL into the target process. Then in the DllMain() of your DLL, call the Windows API GetMenu(hwnd) where hwnd is the frame window of the target.exe.

You can manipulate the menu bar from the returned HMENU.

Cheers,
David
Thanks for your quick answer, but how can I implement the onclick event for the new menu item? Should I hook WM_COMMAND message?
Pacino
Posts: 8
Joined: Thu May 05, 2005 3:17 pm

Post by Pacino »

Well, I use SetWindowsHookEx to solve my problem now. There's still another problem. Can anyone help me? Thank you.

//Loader.exe

uses
madCodeHook
...
CreateProcessEx(nil, 'Target.exe', nil, nil, false, 0, nil, nil, si, pi,'Plugin.dll')
...

//plugin.dll

.....
procedure Hook(ThreadID:DWORD); stdcall;
begin
hNextHook := SetWindowsHookEx(WH_CALLWNDPROC, @CallWndProc, HInstance,ThreadID);
end;

procedure UnHook; stdcall;
begin
if hNextHook <> 0 then
UnhookWindowsHookEx(hNextHook);
end;

function DllMain(dwReason: DWord):boolean;
.....
case dwReason of

DLL_PROCESS_ATTACH:
begin
Hook(ProcID); //ProcID has been initialized
end;
DLL_PROCESS_DETACH:
begin
showMSG('UnHooked');
UnHook;
end;
...................

begin
hNextHook := 0;
DllProc:=@DllMain;
DllMain(DLL_PROCESS_ATTACH);
end.


When I run load.exe, something strange occured. It seems that plugin.dll is injected into explorer.exe and other processes that depend on explorer.exe (namely, has tray icon or minimized to tray), include target.exe. How to solve this tough probelm? I just want plugin.dll injected to my target.exe.

//bow&thanks
dcsoft
Posts: 380
Joined: Sat Dec 11, 2004 2:11 am
Location: San Francisco Bay Area, CA USA
Contact:

Post by dcsoft »

Pacino wrote:Well, I use SetWindowsHookEx to solve my problem now. There's still another problem. Can anyone help me? Thank you.
SetWindowsHookEx() is not really appropriate here. Since your dll is already in the target process, a much simpler way is to subclass the desired window. That involves calling

Code: Select all

SetWindowLong (hwnd, GWL_WNDPROC, (LONG) YourWndProc)
so that YourWndProc gets called for every message sent to hwnd. There, you would handle the WM_COMMAND message generated by your inserted menu item.

-- David
dcsoft
Posts: 380
Joined: Sat Dec 11, 2004 2:11 am
Location: San Francisco Bay Area, CA USA
Contact:

Post by dcsoft »

Pacino wrote:

Code: Select all

hNextHook := SetWindowsHookEx(WH_CALLWNDPROC, @CallWndProc, HInstance,ThreadID);
...

When I run load.exe, something strange occured. It seems that plugin.dll is injected into explorer.exe.
What is ThreadId? If set to 0, you are setting a systemwide hook so your dll would be injected into all other threads of the current desktop. Make sure ThreadId is the thread that created the hwnd you're interested in. To do this call
GetWindowThreadProcessId(hwnd)
But as I said, using a windows hook is totally unnecessary if you're using madCodeHook.

-- David
Pacino
Posts: 8
Joined: Thu May 05, 2005 3:17 pm

Post by Pacino »

dcsoft wrote:
Pacino wrote:Well, I use SetWindowsHookEx to solve my problem now. There's still another problem. Can anyone help me? Thank you.
SetWindowsHookEx() is not really appropriate here. Since your dll is already in the target process, a much simpler way is to subclass the desired window. That involves calling

Code: Select all

SetWindowLong (hwnd, GWL_WNDPROC, (LONG) YourWndProc)
so that YourWndProc gets called for every message sent to hwnd. There, you would handle the WM_COMMAND message generated by your inserted menu item.

-- David
Well, the desired window to hook is a child form. I can't get its handle until it's created by main form. Then how can I use SetWindowLong without the required hwnd?
Pacino
Posts: 8
Joined: Thu May 05, 2005 3:17 pm

Post by Pacino »

dcsoft wrote:
Pacino wrote:

Code: Select all

hNextHook := SetWindowsHookEx(WH_CALLWNDPROC, @CallWndProc, HInstance,ThreadID);
...

When I run load.exe, something strange occured. It seems that plugin.dll is injected into explorer.exe.
What is ThreadId? If set to 0, you are setting a systemwide hook so your dll would be injected into all other threads of the current desktop. Make sure ThreadId is the thread that created the hwnd you're interested in. To do this call
GetWindowThreadProcessId(hwnd)
But as I said, using a windows hook is totally unnecessary if you're using madCodeHook.

-- David
Thank you for your answer :D
ThreadID refers to the Process ID of target.exe (misspelled as ThreadID, sorry). As follows:

Code: Select all

ProcID:=GetCurrentProcessId;
Hook(ProcID);
I'm puzzled why the problem I said would happens.
Maybe SetWindowsHookEx won't take affect in the same process?
dcsoft
Posts: 380
Joined: Sat Dec 11, 2004 2:11 am
Location: San Francisco Bay Area, CA USA
Contact:

Post by dcsoft »

Pacino wrote:Well, the desired window to hook is a child form. I can't get its handle until it's created by main form. Then how can I use SetWindowLong without the required hwnd?
Well, you need the hwnd first thing, or you won't even be able to modify its menu. Remember, you need to do a GetMenu(hwnd) to get the HMENU you want to modify.

What I've done is to use an Active Accessibility hook (SetWinEventHook) to get notified when a new window is created. If it's one I'm interested in, that's when I InjectLibrary() into the process that created it, subclass the window, etc.

In your case, this is better than CreateProcessEx() since you don't need to be injected at process startup, it is better to wait until the desired window is created.

-- David
dcsoft
Posts: 380
Joined: Sat Dec 11, 2004 2:11 am
Location: San Francisco Bay Area, CA USA
Contact:

Post by dcsoft »

Pacino wrote:

Code: Select all

hNextHook := SetWindowsHookEx(WH_CALLWNDPROC, @CallWndProc, HInstance,ThreadID);
...

ThreadID refers to the Process ID of target.exe (misspelled as ThreadID, sorry). As follows:

Code: Select all

ProcID:=GetCurrentProcessId;
Hook(ProcID);
The last parameter to SetWindowsHookEx() needs to be a thread id. Windows belong to threads, so this specifies which thread's windows you will get called for. Don't use a process id, it makes no sense.

-- David
Dracula
Posts: 27
Joined: Thu May 12, 2005 5:30 pm

dcsoft

Post by Dracula »

I'm also interested in this a bit. I created a menu in another program (process other than my own) and I'd like to be able to add functionality to it. Any ideas on using SetWindowLong as you described? I dont really see the point of hooking because the dll is injected in the target process. SetWindowLong(0, GWL_WNDPROC .. or whatever confuses me because there seems to be many window procedures in windows sdk. Lets say I have menu in another program that I appended to it and a user clicks the 3rd item in the menu, how would I try and act on the click event?
any help would be grateful
Dracula
Posts: 27
Joined: Thu May 12, 2005 5:30 pm

subclass dll

Post by Dracula »

Found this online but it doesn't seem to work but it compiles. Anyone know how to get this working as an example on notepad or something similar?

Code: Select all

library MSNHook;

uses
  Windows,
  Messages;

type
  THookRec = record
    hMSNHook: HHOOK;
    hMSNWnd: HWND;
    oldProc: Integer;
  end;

var
  map: DWord;
  buf: ^THookRec;

// msn window proc - runs in context of ms messenger
function MSNWndProc(Handle: hWnd; Msg: uInt; wp: wParam; lp: lParam): LongInt; stdcall;
var
  MiMenu, SysMenu, NewMenu : HMENU;
begin
  try
    case Msg of
      WM_COMMAND:
      begin
        if (wp = $1000) then MessageBox(0, 'Item #1 Clicked', 'Extra IE', MB_OK);
        if (wp = $1001) then MessageBox(0, 'Item #2 Clicked', 'Extra IE', MB_OK);
      end;

      WM_SYSCOMMAND:
      begin
        if (wp = $1002) then MessageBox(0, 'Extra MSN', 'Extra', MB_OK);
      end;

      WM_SHOWWINDOW:
      begin
        SetWindowText(Handle, 'Extra MSN');
        NewMenu := CreatePopupMenu;
        MiMenu := GetMenu(Handle);

        AppendMenu(MiMenu, MF_POPUP, NewMenu, '&Extra Menu');
        AppendMenu(NewMenu, MF_STRING, $1000, '&Item #1');
        AppendMenu(NewMenu, MF_STRING, $1001, 'I&tem #2');

        SysMenu := GetSystemMenu(Handle, False);
        AppendMenu(SysMenu, MF_SEPARATOR, 0, '-');
        AppendMenu(SysMenu, MF_STRING, $1002, '&Extra MSN');
      end;

      // user definied message to stop subclassing
      WM_USER + 1:
      begin
        // delete custom menu entries (quick'n'dirty)
        SetWindowLong(buf^.hMSNWnd, GWL_WNDPROC, buf^.oldProc);
        DeleteMenu(GetMenu(Handle), GetMenuItemCount(GetMenu(Handle)) - 1, MF_BYPOSITION);
        DrawMenuBar(GetMenu(Handle));
        DeleteMenu(GetSystemMenu(Handle, False), GetMenuItemCount(GetMenu(Handle)) - 1, MF_BYPOSITION);
        DeleteMenu(GetSystemMenu(Handle, False), GetMenuItemCount(GetMenu(Handle)) - 2, MF_BYPOSITION);
        DrawMenuBar(GetMenu(Handle));
      end;

    end;
    Result := CallWindowProc(Pointer(buf^.oldProc), Handle, Msg, wp, lp);
  except
    Result := 0;
    MessageBox(0, 'error in MSNWndProc', 'error', MB_OK);
  end;
end;

// hook proc - waits for msn window to be created
function MSNHookProc(nCode: Integer; wp: wParam; lp: lParam): LongInt; stdcall;
var
  hTemp: hWnd;
  szClass: array[0..255] of Char;
begin
  try
    if (nCode >= HC_ACTION) then
    begin
      Case nCode of
        HCBT_CREATEWND:
        begin
          hTemp := HWND(wp);
          FillChar(szClass, 256, 0);
          GetClassName(hTemp, szClass, 256);
          if (szClass = 'MSBLClass') then
          begin
            buf^.hMSNWnd := hTemp;
            buf^.oldProc := GetWindowLong(buf^.hMSNWnd, GWL_WNDPROC);
            SetWindowLong(buf^.hMSNWnd, GWL_WNDPROC, Integer(@MSNWndProc));
          end;
        end;
        HCBT_DESTROYWND:
        begin
          hTemp := HWND(wp);
          FillChar(szClass, 256, 0);
          GetClassName(hTemp, szClass, 256);
          if (szClass = 'MSBLClass') then
          begin
            SetWindowLong(buf^.hMSNWnd, GWL_WNDPROC, buf^.OldProc);
          end;

        end;
      end;
    end;
    Result := CallNextHookEx(buf^.hMSNHook, nCode, wp, lp);
  except
    Result := 0;
    MessageBox(0, 'error in MSNHookProc', 'error', MB_OK);
  end;
end;

// sets up hook
function SetHook: Boolean; stdcall; export;
begin
  try
    Result := false;
    if (not assigned(buf)) then
    begin
      map := CreateFileMapping(DWord(-1), nil, PAGE_READWRITE, 0, SizeOf(THookRec), 'HookRecMemBlock');
      buf := MapViewOfFile(map, FILE_MAP_ALL_ACCESS, 0, 0, 0);
      buf^.hMSNHook := SetWindowsHookEx(WH_CBT, @MSNHookProc, hInstance, 0);
      Result := true;
    end;
  except
    Result := false;
    MessageBox(0, 'error in SetHook', 'error', MB_OK);
  end;
end;

// removes hook
function RemoveHook: Boolean; stdcall; export;
begin
  Result := false;
  if (assigned(buf)) then
  begin
    // tell our new msn wnd proc to stop subclassing
    // (has to be done in context of msn)
    SendMessage(buf^.hMSNWnd, wm_User + 1, 1, 0);
    if (buf^.hMSNHook <> 0) then UnhookWindowsHookEx(buf^.hMSNHook);
    buf^.hMSNHook := 0;
    UnmapViewOfFile(buf);
    buf := nil;
    Result := true;
  end;
end;

// DLL entry point
procedure DllEntry(dwReason: DWord);
begin
  Case dwReason of
    DLL_PROCESS_ATTACH:
    begin
      if (not assigned(buf)) then
      begin
        map := OpenFileMapping(FILE_MAP_ALL_ACCESS, false, 'HookRecMemBlock');
        buf := MapViewOfFile(map, FILE_MAP_ALL_ACCESS, 0, 0, 0);
        CloseHandle(map);
        map := 0;
      end;
    end;
    DLL_PROCESS_DETACH:
    begin
      UnmapViewOfFile(buf);
      buf := nil;
    end;
  end;
end;

exports
  SetHook,
  RemoveHook;

// main
begin
  DisableThreadLibraryCalls(hInstance);
  DllProc := @DLLEntry;
  DllEntry(DLL_PROCESS_ATTACH);
end.
dcsoft
Posts: 380
Joined: Sat Dec 11, 2004 2:11 am
Location: San Francisco Bay Area, CA USA
Contact:

Re: dcsoft

Post by dcsoft »

Dracula wrote:I'm also interested in this a bit. I created a menu in another program (process other than my own) and I'd like to be able to add functionality to it. Any ideas on using SetWindowLong as you described? I dont really see the point of hooking because the dll is injected in the target process. SetWindowLong(0, GWL_WNDPROC .. or whatever confuses me because there seems to be many window procedures in windows sdk. Lets say I have menu in another program that I appended to it and a user clicks the 3rd item in the menu, how would I try and act on the click event?
any help would be grateful
The only thing you would use madCodeHook for is for DLL injection. Once your DLL is injected, you need to :

HMENU hMenu = GetMenu(hwnd)
AppendMenu (hMenu), <your menu item>

Then you need to subclass hwnd so you can react to WM_COMMAND messages generated by <your menu item>

SetWindowLong (hwnd, GWL_WNDPROC, <your proc>)

Then you need to handle the WM_COMMAND message in <your proc>

Code: Select all

function YourProc(Handle: hWnd; Msg: uInt; wp: wParam; lp: lParam): LongInt; stdcall; 
begin 
  try 
    case Msg of 
      WM_COMMAND: 
      begin 
        if (wp = <your menu item id>) then MessageBox(0, 'My appended Item Clicked', 'Extra IE', MB_OK);
Hope this helps,
David[/code]
Dracula
Posts: 27
Joined: Thu May 12, 2005 5:30 pm

dcsoft

Post by Dracula »

i'll look at what you said to do, i started with this using vcl in my application.

Code: Select all

var
    mnu: HMENU;
 struct: TMENUITEMINFO;
     mm: TMAINMENU;
    itm: TMENUITEM;
      h: hWnd;

Procedure MakeMenu();
const txt: pchar = 'test';
 begin
  mm := TMainMenu.Create(nil);
//  itm := TMenuItem.Create(mm);
 try
 // itm.Caption := 'test';
 // mm.Items.Add(itm);
  h := FindWindow(nil, 'window_caption_of_target');
  if ( h <> 0 ) then
  mnu := GetMenu(h);
  if ( mnu <> NULL ) then
 begin
  DrawMenuBar(h);
  appendmenu(mnu, MF_STRING, mm.handle, txt);
  DrawMenuBar(h);
  end;
 finally
  end;
 end;
seems to append fine but the popup is weird on mouse over event
Dracula
Posts: 27
Joined: Thu May 12, 2005 5:30 pm

..

Post by Dracula »

Okay I'll mess with it when I get home from work today a bit more. I'm new to injecting dlls and window subclass stuff, sry i'm a noobie :(

Here's what i've been playing around with

Code: Select all

library injct;

// nmnu = Handle to New Menu
// mnu = Handle to the Target Menu We're Appending

uses
messages, windows;

 Function WndProc(Handle: hWnd; Msg: uInt; wp: wParam; lp: lParam): LRESULT; stdcall;
 begin
  case Msg of
  WM_COMMAND:
    begin
    if (wp = $1000) then MessageBoxA(0, 'My appended Item Clicked', 'Extra', MB_OK);
    if (wp = $1001) then MessageBoxA(0, 'My 2nd appended Item Clicked', 'Extra', MB_OK);
    end;
   end;
 end;

  Procedure MenuConstructor(); stdcall
   var h: THandle;
   mnu, nmnu: HMENU;
   pid: cardinal;
   begin
     PID := GetCurrentProcessID();
      h := Openprocess(PROCESS_ALL_ACCESS, bool(0), PID);
      mnu := GetMenu(h);
      nmnu := CreatePopupMenu();
      AppendMenu(mnu, MF_POPUP, nmnu, '&Extra Menu');
      AppendMenu(nmnu, MF_STRING, $1000, '&Item #1');
      AppendMenu(nmnu, MF_STRING, $1001, 'I&tem #2');
      DrawMenubar(h);
      SetWindowLong(h, GWL_WNDPROC, LongInt(@WndProc));
      DrawMenuBar(h);
      end;

 procedure DllEntry(dwReason: DWORD);
 begin
 Case dwReason of
 DLL_PROCESS_ATTACH:
 begin

 end;
 DLL_PROCESS_DETACH:
 begin

  end;
    end;
     end;

begin
DllProc := @DLLEntry;
DllEntry(DLL_PROCESS_ATTACH);
end.
Any additional help ontop of what dcsoft has helped me with would be swell as I'd like to see it done cuz it interests me :)

Thanks!
Post Reply