微信hook的原理分享与讨论教程类似写辅助

文章资讯 2020-01-19 13:36:54

微信hook的原理分享与讨论教程类似写辅助

一、注入自己的dll。
一些教程视频中,易语言的注入就一句代码。etcp的一个模块。我能力有限,手头也没有现成的代码。所以就像还是用键盘hook的方式注入。后期在考虑进程间通讯做群控。另外就是觉得在dll里面写窗口似乎简单一点。
键盘hook注入的相关代码如下

function installKeyhook: Boolean; stdcall;var
  h: hwnd;
  GameTid: THandle;
begin
  Result := False;
  h := FindWindow('WeChatLoginWndForPC', nil);
  if h = 0 then
  begin
    h := FindWindow('WeChatMainWndForPC', nil);
    if h = 0 then
    begin
      MessageBox(0, '未找到微信窗口', '提示', 0);
      exit;
    end;
  end;
  GameTid := GetWindowThreadProcessId(h);
  keyhhk := SetWindowsHookEx(WH_KEYBOARD, @keyhook, GetModuleHandle('WeHelp.dll'), GameTid);
  if keyhhk > 0 then
  begin
    Result := True;
  end;
end;

function keyhook(icode, wp, lp: Integer): LRESULT; stdcall;
begin
  if (icode = HC_ACTION) then
  begin
    if (wp = VK_HOME) and ((1 shl 31) and lp = 0) then
    begin
      if Form_main = nil then
      begin
        Form_Main := TForm_Main.Create(nil);
      end;
      Form_Main.Visible := not Form_Main.Visible;
    end;
  end;
  Result := CallNextHookEx(keyhhk, icode, wp, lp);
end;

dll中加上以上代码,在注入exe中调用,就实现了键盘hook注入 。我是hook了home键。
二、微信消息的hook。这个网上有很多查找hook位置的教程。我纠结了很久的是易语言所谓的超级hook功能。

每次微信接受消息就会运行图示这段asm,网上传的inlinehook 就是在790028c3的位置jmp至自己的内存位置,然后运行自己的代码,自己代码运行完后运行 原来790028c3位置的mov ecx,0x7A2DFA20
然后再jmp会790028c8 继续微信的运行。也就是再微信每次接受消息的时候运行一段自己的代码,比如说把消息内容保存下来,这就是所谓的微信消息hook。
delphi写的时候没什么参考。jmp跳转实在写的有点乱。所以我直接修改790028c3位置的代码为call我的自设代码。运行完成后再retn回来。期间用全局变量把寄存器值都截取下来了。关键代码如下:

Fhookaddr := AHookAddr;
FByteLen := ByteLength;
FMyproc := Integer(DspProc);
FOldCode := GetMemory(SizeOf(Pointer) + FByteLen * sizeof(Byte));  //申请FOldCode空间
CopyMemory(FOldCode, Pointer(FHookAddr), FByteLen * sizeof(Byte));
FMyAsm2 := GetMemory(100 * SizeOf(Byte));   //申请FMyAsm空间
VirtualProtect(FMyAsm2, 100 * sizeof(Byte), PAGE_EXECUTE_READWRITE, @oldprotect);      //调整FmyAsm内存空间可读写
FillMemory(FMyAsm2, 100 * SizeOf(Byte), $90);             //初始化空间全部为nop
temp := Integer(Self);                         //temp赋值为superhook自身指针
PByte(Integer(FMyAsm2))^ := $60;       //pushad
PByte(Integer(FMyAsm2) + 1)^ := $C7;      //mov
Pbyte(Integer(FMyAsm2) + 2)^ := $C1;   //ecx
PInteger(Integer(FMyAsm2) + 3)^ := temp;      //self
CopyMemory(Pointer(Integer(FMyAsm2) + 7), @codearr, 73 * sizeof(Byte));   //codeArr写入,内容为将寄存器的值取出至对象字段
Pbyte(Integer(FMyAsm2) + 81)^ := $E8;             //call
PInteger(Integer(FMyAsm2) + 82)^ := FMyProc - Integer(FMyAsm2) - 82 - 4;  //FMyProc的地址
PByte(Integer(FMyAsm2) + 86)^ := $61;              //popad
CopyMemory(Pointer(Integer(FMyAsm2) + 87), FOldCode, FByteLen * sizeof(Byte));  //运行截取过来的值
PByte(Pointer(Integer(FMyAsm2) + 88 + Fbytelen))^ := $C2;    // 在内存字段的最终写下(retn )
Pword(Pointer(Integer(FMyAsm2) + 89 + Fbytelen))^ := $0000;
HookAddr;

三、通讯录的读取。
网络教程是类似消息截取一样再登陆的时候做了一个hook。但是像我这样只用一个账号,且用键盘hook的模式,就感觉不是很方面。总感觉有很多时候是开启微信以后再注入的。
所以我想总归有一个地方存储了通讯了的相关讯息。于是分以下几步描述下(截图实在他麻烦,有ce,od基础的我想应该能理解我说的):
1、ce搜索微信特定名称,比如讨厌的人1111
2、不停切换,最小化,最大化,再搜索讨厌的人1111,ce数据再50以内。
3、修改一半的数据为讨厌的人2222,通过是否改变通讯录名称来筛选数据。
4、重复3确认讨厌的人1111的内存地址。
5、od追溯内存地址偏移。发现通讯录存储为典型的二叉树结构如下:
接下来就是通过找到的二叉树根。对二叉树进行遍历。我只会递归的二叉遍历,代码如下:

procedure AddListTraver;
 
  procedure DoAddListTraver(ARoot: Integer);
  begin
 
    if pbyte(ARoot + $D)^ = 0 then
    begin
      //Form_Client.DspMsg(ARoot.ToHexString);
      SetLength(arr_Addlist, Length(arr_Addlist) + 1);
      arr_Addlist[High(arr_Addlist)] := ARoot;
      DoAddListTraver(pinteger(ARoot + $8)^);
      DoAddListTraver(pinteger(ARoot)^);
    end;
  end;
 
var
  addr: LongInt;
  base: LongInt;
  header: DWORD;
begin
  SetLength(arr_Addlist, 0);
  SupermemScan(AddrListSig, GetModuleHandle('WeChatWin') + $1000, GetModuleHandle('WeChatWin') + $1000 + $400000, addr);
  addr := addr - $4;
  base := Pdword(addr)^;
  header := pdword(pdword(pdword(base)^ + $28 + $84)^ + $4)^;
  //二叉遍历
//  DoAddListTraver(pdword(header)^);
//  DoAddListTraver(pdword(header + $8)^);
  DoAddListTraver(header);
 
end;

四、消息发送call。delphi写的难点似乎就是构造以下消息及id的结构。实现代码如下:

procedure SendMsg(wx_ID, Amsg: string; aite: string = '');
type
  Tmsg = record
    content: PChar;
    len1: LongInt;
    len2: LongInt;
  end;
var
  p_ID, Pamsg, paite: TMsg;
  callAddr: LongInt;
  buff: array[0..$87c] of Byte;
  p1, p2, p3: Pointer;
begin
  SupermemScan(SendCallSig, GetModuleHandle('WeChatWin') + $1000, GetModuleHandle('WeChatWin') + $1000 + $100000, callAddr);
  callAddr := callAddr + $F + pdword(callAddr + $b)^;
  p_ID.content := PChar(wx_ID);
  p_ID.len1 := Length(wx_ID);
  p_ID.len2 := Length(wx_ID) * 2;
  Pamsg.content := PChar(Amsg);
  Pamsg.len1 := Length(Amsg);
  Pamsg.len2 := Length(Amsg) * 2;
  if aite = '' then
  begin
    paite.content := nil;
  end
  else
  begin
    paite.content := PChar(aite);
  end;
  paite.len1 := Length(aite);
  paite.len2 := Length(aite) * 2;
  p1 := @p_ID;
  p2 := @Pamsg;
  p3 := @paite;
  asm
        mov     edx, p1;
        mov     eax, p3;
        push    1;
        push    eax;
        mov     ebx, p2;
        push    ebx;
        lea     ecx, buff;
        call    calladdr;
        add     esp, $C;
  end;
 
end;

这段代码我自己都觉得挺烂的 尤其 p1 p2 p3那段,欢迎介绍一些更好的写法。
我自己还有一些不清楚的地方:
1、做群控的话,涉及进程间通信,delphi没有易语言那种一句话代码,不知道用什么组件实现比较合适。
2、上面的这些代码  尤其是发信的这段 挺烂的  有没有大佬优化下。
3、注入的方式我自己熟悉的只有键盘hook ,还有远程线程注入。但以前捣鼓的时候 ,还有远程线程注入。就微信hook ,那种比较合适,为啥。