麻烦大家帮忙看下,dll注入后,可自动显示窗口,但是 键盘钩子也勾上了,但是没法呼出窗口,加了个 MessageBox(0,'直接显示' ,'显示',0);,会显示。还有动态调用dll会提示找不到函数,静态没问题,函数有带参数的,搞的有点晕
dll代码入下
library mydll;
uses
  SysUtils,
  Windows,
  Classes,
  Forms,
  myform in 'myform.pas',var
  keyhhk:HHOOK;
{$R *.res}function keyproc(icode,wp,lp:integer):dword;stdcall;
begin
  if (icode=HC_ACTION) then
    begin
       if (wp=VK_HOME)and ((1 shl 31)and lp=0) then
        begin
        if form1=nil then
        begin
        form1:=tform1.Create(nil);
        //MessageBox(0, PChar(IntToStr(Application.Handle)), PChar('Test'), MB_OK);
        MessageBox(0,'成功' ,'显示',0);
        end;
        form1.Show;
        MessageBox(0,'显示' ,'显示',0);
        end;
    end;
   keyproc:=CallNextHookEx(keyhhk,icode,wp,lp);
end;procedure DllEnterProc(reason:DWord);    //卸载函数窗体begin
   case reason of
   windows.DLL_PROCESS_ATTACH:
   begin
   //hookdlla:=Thookdll.Create(false);
   form1:=tform1.Create(nil);
   form1.Show;
   MessageBox(0,'进入' ,'显示',0);
   end;
   windows.DLL_PROCESS_DETACH: begin form1.Free; form1:=nil; end;
   end;
end;function installKeyProcy(tid:dword):boolean;stdcall;begin
  Result:=false;
  keyhhk:=setwindowshookex(WH_KEYBOARD,@Keyproc,GetModuleHandle('123.dll'),Tid);  if keyhhk>0 then Result:=true;
end;function uninstallKeyProc():boolean;stdcall;
begin
  Result:=UnhookWindowsHookEx(keyhhk);
end;exportsinstallKeyProcy,
uninstallKeyProc;
begin
dllproc:=@DllEnterProc;
DllEnterProc(DLL_PROCESS_ATTACH);end.
exe窗口用上 InjectDll(ExtractFilePath(Application.ExeName) +'123.dll',lsPid);
会运行 windows.DLL_PROCESS_ATTACH 的内容。
我再同时用上
installKeyProcy(tid) 是会钩住程序,也会显示 MessageBox(0,'显示' ,'显示',0);的内容,但是窗口不会显示出来。我的目的是要注入后能自动能显示窗口,并且我按键时也能弹出窗口,不知哪里出错了,请大家指导下。
还有 installKeyProcy(tid)用静态调用没问题,用    hModule:=LoadLibrary(123.dll');
   Pcall:=GetProcAddress(hModule,  installKeyProcy);
   installKeyProcy:=Pcall;
   if (Pcall=nil) then
   begin
   self.Caption:='未成功获取函数地址';
   exit;
   end;
会弹出 '未成功获取函数地址',如果是调用不带参数的却没有问题,这个也请大家指导下

解决方案 »

  1.   

    既然MessageBox(0,'显示' ,'显示',0)
      

  2.   

    Pcall:=GetProcAddress(hModule,  installKeyProcy);// 第二个参数错了当然取不到函数地址,而且根本不能通过编译,你是怎么编译成功的??改:
    Pcall:=GetProcAddress(hModule,  'installKeyProcy'); // 第二个参数是函数名
      

  3.   

    楼上好眼力,那个是我复制下来时改错了,程序是有加''的,要不是没法编译成功,问题不是出在这的,会不会 第一次 form1:=tform1.Create(nil); 创建的form1 跟 弟2次 form1.Show 不是同一个form,但是 if form1=nil then 这句判定不为空,也就是说弟2次只运行了 form1.Show,但是不会显示出来,很纠结啊
      

  4.   

    论坛真奇怪。。把我#1老长的一段话截成一句。。我想说:试试把form1.show改成form1.showmodal
      

  5.   

    论坛真奇怪。。把我#1老长的一段话截成一句。。我想说:试试把form1.show改成form1.showmodal
      

  6.   

    论坛真奇怪。。把我#1老长的一段话截成一句。。我想说:试试把form1.show改成form1.showmodal
      

  7.   


    function keyproc(icode, wp, lp: integer): DWORD; stdcall;
    begin
      if (icode = HC_ACTION) then
      begin
        if (wp = VK_HOME) and ((1 shl 31) and lp = 0) then
        begin
          if form1 = nil then
            form1:= tform1.Create(nil);// 按键注入dll后立即创建窗体
          else
            form1.Visible := not form1.Visible; //如果之前已经创建过那么就切换显示状态
        end;
      end;
      keyproc:=CallNextHookEx(keyhhk,icode,wp,lp);
    end;
      

  8.   

    切换完状态窗口要置顶:form1.bringtofront
      

  9.   

    keyproc中的执行环境应当是被注入线程的执行环境,这样相当于在非主线程操作界面,不是线程安全的。
    试试在主线程中创建窗体,然后keyproc中用SendMessage发送一个自定义消息给窗体,窗体响应消息时Show窗体,这样就是在主线程操作界面了。
      

  10.   

    to ls, lz看来是想做网游外挂,而又不想用写入远程代码的方式,用注入宿主(游戏)进程以使用各种便利是它的目的(而且不少网游都是做过禁止写入远程代码处理的)。LZ那个只不过是很简单的逻辑问题,安小弟上面的代码就可以解决了。
      

  11.   

    感谢各位的指导,sololie 的代码跟我的是一样的,只用  keyproc钩子的话 如果按下 home键时可以运行,问题是我的目的是要,注入后就能先创建窗口,按下home也能显示出那个窗口而不是等按下home再来运行创建窗口的代码,把dll注入到程序我是用的是 InjectDll(ExtractFilePath(Application.ExeName) +'123.dll',lsPid); 代码入下,
    function InjectDll(const DllFullPath : string;
      const dwRemoteProcessId : Cardinal): boolean;
    var
      hRemoteProcess, hRemoteThread: THANDLE;
      pszLibFileRemote : Pointer;
      pszLibAFilename: PwideChar;
      pfnStartAddr : TFNThreadStartRoutine;
      memSize, WriteSize, lpThreadId : Cardinal;
    begin
      result := FALSE;
      // 调整权限,使程序可以访问其他进程的内存空间
      if EnableDebugPriv then
      begin
        //打开远程线程 PROCESS_ALL_ACCESS 参数表示打开所有的权限
        hRemoteProcess := OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId );    try      // 为注入的dll文件路径分配内存大小,由于为WideChar,故要乘2
          GetMem(pszLibAFilename, Length(DllFullPath) * 2 + 1);
          // 之所以要转换成 WideChar, 是因为当DLL位于有中文字符的路径下时不会出错
          StringToWideChar(DllFullPath, pszLibAFilename, Length(DllFullPath) * 2 + 1);
          // 计算 pszLibAFilename 的长度,注意,是以字节为单元的长度
          memSize := (1 + lstrlenW(pszLibAFilename)) * sizeof(WCHAR);      //使用VirtualAllocEx函数在远程进程的内存地址空间分配DLL文件名空间
          pszLibFileRemote := VirtualAllocEx( hRemoteProcess, nil, memSize,
            MEM_COMMIT, PAGE_READWRITE);      if Assigned(pszLibFileRemote) then
          begin        //使用WriteProcessMemory函数将DLL的路径名写入到远程进程的内存空间
            if WriteProcessMemory(hRemoteProcess, pszLibFileRemote,
              pszLibAFilename, memSize, WriteSize) and (WriteSize = memSize) then
            begin          lpThreadId := 0;
              // 计算LoadLibraryW的入口地址
              pfnStartAddr := GetProcAddress(LoadLibrary('Kernel32.dll'), 'LoadLibraryW');
              // 启动远程线程LoadLbraryW,通过远程线程调用创建新的线程
              hRemoteThread := CreateRemoteThread(hRemoteProcess, nil, 0,
                pfnStartAddr, pszLibFileRemote, 0, lpThreadId);          // 如果执行成功返回 True;
              if (hRemoteThread <> 0) then
                result := TRUE;          // 释放句柄
              CloseHandle(hRemoteThread);
            end;
          end;
        finally
          // 释放句柄
          CloseHandle(hRemoteProcess);
        end;
      end;
    end;
    也是网上找的,可以把dll直接注入到程序里面,查询了程序的模块,dll已经被注入了,
    这个注入后会调用 DllEnterProc里面的代码,窗口也有创建了,但是当我按下home键时 窗口是不会显示的,但是会弹出‘显示’这个框框,也就是说 form1.show 有运行,但是没效果,用上了form1.Visible := not form1.Visible也一样,用了 728 指导的那个 showmodal 注入的程序直接卡住,是不是 DllEnterProc代码里面创建的form1和keyproc代码里面创建的form1不一样呢?本人愚钝,还请大家多多指导
      

  12.   

    唉尽力了。。我只懂远程拦截不懂远程本地拦截。。不过我怎么都觉得在DLL用类有点不妥,我写dll都直接用API的
      

  13.   

    还是那句话,既然MessageBox显示出来了说明其他地方逻辑没问题,有问题的地方只是类的创建那儿。。
      

  14.   

    类是指窗口吗,本人基础实在是薄弱,还有 function installKeyProcy(tid:dword):boolean;stdcall;
    ,这个用静态的可以,动态的就不行了
       hModule:=LoadLibrary(123.dll');
       Pcall:=GetProcAddress(hModule,  'installKeyProcy');
       installKeyProcy:=Pcall;
       if (Pcall=nil) then
       begin
       self.Caption:='未成功获取函数地址';
       exit;
       end;
    会提示 '未成功获取函数地址',没带参数的函数却是可以的,这个也是很让人郁闷,诸多问题困扰着我,唉
      

  15.   

    s11ss兄,你说的方法有个例子代码吗,’试试在主线程中创建窗体,然后keyproc中用SendMessage发送一个自定义消息给窗体,窗体响应消息时Show窗体,这样就是在主线程操作界面了。‘,这句话我看得蒙蒙的,怎么实现呢,‘SendMessage发送一个自定义消息给窗体’这个怎么弄,’窗体响应消息时Show窗体‘这个要如何实现,唉
      

  16.   

    type TinstallKeyProcy function(tid:dword):boolean
      

  17.   

    type TinstallKeyProcy function(tid:dword):boolean;stdcall;
    var
    installKeyProcy:TinstallKeyProcy;
    begin
       hModule:=LoadLibrary(123.dll'); installKeyProcy:=GetProcAddress(hModule,  'installKeyProcy');
       if (installKeyProcy=nil) then
       begin
       self.Caption:='未成功获取函数地址';
       exit;
       end;
    end;
    这样才行,这才是标准调用,还有GetProcAddress的参数名'installKeyProcy'要和DLL中命名大小写一致。
      

  18.   

    type TinstallKeyProcy= function(tid:dword):boolean;stdcall;
      

  19.   

    谢谢728兄,'installKeyProcy'的动态调用可以了,我只是依葫芦画瓢,呵呵。请大家帮忙看下另外一个问题,就是上面那个窗口不会显示的问题,这个问题有点纠结
      

  20.   

    第一次加载DLL时 MessageBox(0,'成功' ,'显示',0);有没有显示?
      

  21.   

    哦,对了,尽量不要使用form1这个变量,你应该在dll工程文件中定义一个form变量取代form1。。我以前就是因为这样出了问题。。
    对了,你还可以监控一下:既然form.show无法显示,那你试试MessageBox(0,IntToStr(form.Handle),'Tips',MB_OK);显示什么?这个方法可以查看你的窗口是否正常创建。
      

  22.   


    function keyproc(icode, wp, lp: integer): DWORD; stdcall;
    begin
      if (icode = HC_ACTION) then
      begin
        if (wp = VK_HOME) and ((1 shl 31) and lp = 0) then
        begin
          if form1 = nil then
            form1:= tform1.Create(nil);// 按键注入dll后立即创建窗体
          else
            form1.Visible := not form1.Visible; //如果之前已经创建过那么就切换显示状态
        end;
      end;
      keyproc:=CallNextHookEx(keyhhk,icode,wp,lp);
    end;窗体执行create就已经包含能显示了,你挂钩后按下home键的同时就把创建窗体和显示窗体一并完成了,
    也就是说你首次按下home,dll中的窗体就会显示出来,如果已经不是第一次按下home就证明form1已经存在一个实例,你只需要改变它的Visible属性即可,都说了这根本就是逻辑问题而已。你都没搞清楚你是怎么注入的,你用的是键盘钩子,你不按键dll就根本没有注入,你必须按键home了才把dll注入进去,然后才能做其他的事。
    我用上面的代码测试把dll注入写字板,首次按下home就能显示窗体,再按下就隐藏。
      

  23.   

    “注入后就能先创建窗口,按下home也能显示出那个窗口而不是等按下home再来运行创建窗口的代码”
    那你试试在dll的入口函数中进程附加那个case中处理看看
      

  24.   

    给lz你个完整的示例,注入系统自带的计算器的,按home键显示dll中的窗体,完全满足本贴的需求http://pan.baidu.com/share/link?shareid=98237&uk=1124482001
      

  25.   

    谢谢大家的解答,sololie兄发的程序 是一个单纯按键钩子的程序,和我只运行installKeyProcy是一样的效果,要等按下home键才回建立并显示窗口,而我的需要时,注入后立即创建窗口,按下home键也能显示窗口,而不是单纯等到按下home键才来创建。 
    下面这个就是入口函数,
    procedure DllEnterProc(reason:DWord);    
    begin
       case reason of
       windows.DLL_PROCESS_ATTACH:
       begin
       //hookdlla:=Thookdll.Create(false);
       form1:=tform1.Create(nil);
       form1.Show;
       MessageBox(0,'进入' ,'显示',0);
       end;
       windows.DLL_PROCESS_DETACH: begin form1.Free; form1:=nil; end;
       end;
    end;当我用 InjectDll(ExtractFilePath(Application.ExeName) +'123.dl,这个注入dll到程序时是会弹出提示的,入口函数有运行,同时我在InjectDll这句后面加了个安装钩子的installKeyProcy,这样按下home才有反应,但是,按下home键后窗口却没有显示出来,只弹出提示,如果只运行installKeyProcy而没运行InjectDll,要等按下home时dll才会在程序里面找到,并且窗口有显示,不会只弹出提示,我的主要问题就是,既要第一次注入后马上创建窗口,而不是等我按下home再来创建