中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 看雪学院专区 > Win32/Win64编程
控制其他程序内部函数-第二部分(汇编源代码)
作者:回心转意 时间:2006-12-15 14:50 出处:pediy.com 责编:月夜寒箫
              摘要:控制其他程序内部函数-第二部分(汇编源代码)
今天用了一天的时间在调试第二部分代码,本以为在昨天代码的基础上实现第二部分功能应该比较简单,没想到还是费了不少力气,呵呵。
    好了,还是先说下大体思路,如果需要调用其它进程的内部函数做自己的事情,那么必须先把需要调用的函数的参数传递给目标函数,要实现这个功能我还是选用管道通信技术,毕竟上一部分已经建立了一个管道。然后由我们的程序把参数利用管道发给已经插入到目标进程中的DLL,DLL收到参数后,进行相应处理,组织好参数的格式,然后根据需要调用的函数要求,逐个压入堆栈,然后CALL目标函数执行。
    我们先来做DLL部分,需要以下步骤。
1、在DLL初始化时,建立一个新的线程用来接收函数的参数并调用目标函数。可能大家会觉得奇怪,为什么要建立新的线程,用DLL初始化的线程不行么?我开始也不想建立新线程,可是没想到利用DLL初始化线程的时候会导致DLL初始化无法结束,因为我们的接收过程是个死循环,所以必须建立新线程,否则目标进程会卡死在我们的DLL初始化过程。
2、在线程内添加代码构建一个死循环,用来读取管道内发送过来的数据。
3、根据数据内容进行判断,是否调用目标函数。为什么会有这一步呢,因为我在调试的过程中发现读取管道的函数ReadFile,是一个同步的函数,就是说它如果读不出来数据,就会一直卡在那里,导致整个目标进程无法正常运转。所以我在管道的服务器端同样构建了一个循环,一直发送01这个字节集到管道,所以DLL的接收端就能不断从管道内读出01这个字节。所以要加入这个判断,如果读出的字节是01那么就不处理这个数据。
4、如果收到的数据的第一个字节大于01,那么即可开始组织数据,压入堆栈,调用函数。
下面看下汇编原代码:
    .386
    .model flat, stdcall
    option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include    windows.inc
include    user32.inc
includelib  user32.lib
include    kernel32.inc
includelib  kernel32.lib
includelib  ws2_32.lib
include    ws2_32.inc

PATCH_POSITION  equ     005609ebh
WSASendBuf  struct      ;需要调用的目标函数中的一个参数的结构
  dwSize  dd  ?
  dwAddr  dd  ?
WSASendBuf ends
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .data?
hModel  dd  ?      ;本模块入口地址
dwAddress  dd  ?    ;跳转回去的目标地址
lpBuffers  dd  ?    ;数据包地址

dwProcAddr  dd  ?    ;跳转函数的入口地址
    
hPipe    dd  ?    ;管道句柄
dwSize    dd  ?    ;已经发送数据的长度、字节
dwMemAdd  dd  ?    ;发送数据的地址
dwPackSize  dd  ?    ;需要发送数据的长度、字节
lpBufRecv  dd  ?    ;接收管道数据包地址
szBuffer  db  1024 dump (?)  ;数据处理空间
hSocket    dd  ?    ;SOCKET句柄
dwWsasend  WSASendBuf  <>
dwSizePipe  dd  ?    ;模拟发送的数据长度
hRecvPipe  dd  ?    ;用于接受管道数据的管道句柄
dwRecvThreadID  dd  ?
dwCode    dd  ?
  .const
szText  db  '再如成功',0
szProc  db  '_lanjie',0
szModel  db  'mylib.dll',0
szPipeName  db  '\\.\Pipe\masm',0
szRecvPipeName  db  '\\.\Pipe\Recv',0






;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .code
_Recv proc
 invoke WaitNamedPipe,addr szPipeName,500h    ;建立管道连接
 
 invoke CreateFile,addr szPipeName,GENERIC_READ or GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,NULL
 mov hPipe,eax
                             

 mov eax,offset szBuffer
 mov lpBufRecv,eax
;构建死循环,读取管道数据
.while TRUE
 invoke ReadFile,hPipe,lpBufRecv,1024,offset dwSizePipe,NULL 
 mov al,byte ptr [szBuffer]
 
   .if  al>1      ;判断是否为有用的数据
     mov eax,dwSizePipe  ;组织函数参数
     mov dwWsasend.dwSize,eax
     mov eax,offset lpBufRecv
     mov dwWsasend.dwAddr,eax
     push 0      ;参数开始入栈
     push 0
     push 0
     push offset dwSizePipe
     push 1
     push offset dwWsasend
     push hSocket
     mov eax,dword ptr [0057c75ch]    ;0057c75c地址处的内容就是目标函数的入口地址
     mov eax,[eax]
     call eax        ;调用目标函数
     
   
   .endif   
 .endw
  
  ret

_Recv endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DllEntry  proc  _hInstance,_dwReason,_dwReserved
               
                mov     eax,_dwReason

                .if     eax ==  DLL_PROCESS_ATTACH

                        invoke  MessageBox,NULL,addr szText,addr szModel,MB_OKCANCEL
                                                
                        invoke  GetModuleHandle,addr szModel  ;获得插入DLL函数入口地址
                        mov hModel,eax
                        invoke  GetProcAddress,hModel,addr szProc
                        mov dwProcAddr,eax
                        
                        mov  edx,005609ebh    ;修改参数代码跳转到本函数
                        mov al,0e9h
                        mov byte ptr [edx],al
                        sub dwProcAddr,005609ebh
                        sub dwProcAddr,5
                        mov eax,dwProcAddr
                        mov dword ptr [edx+1],eax
                        
                        mov dwAddress,005609f0h
                        
                        

 

 invoke CreateThread,NULL,0,offset _Recv,NULL,NULL,addr dwRecvThreadID
 

 


                       



      
      ;mov  edx,00560a05h  ;跳过错误检测
      ;mov byte ptr [edx],90h
      ;mov byte ptr [edx+1h],90h
      
                        ;invoke  MessageBox,NULL,addr szText,addr szModel,MB_OKCANCEL
                        
                        ;invoke  Sleep,9000000

                        ;初始化库需要的各种资源

                        .if     ;初始化成功

                            ;mov     eax,TRUE

                        .else

                            ;mov eax,FALSE

                        .endif

                .elseif eax ==  DLL_THREAD_ATTACH

                    ;释放库使用的资源

                .elseif eax ==  DLL_THREAD_DETACH

                    ;为新的线程分配资源

                .elseif eax ==  DLL_PROCESS_DETACH

                    ;为线程释放资源

                .endif

                ret


DllEntry  Endp




_lanjie  proc    ;获得参数地址,并发送数据
  
push eax
push 1
push esi
push ecx
mov lpBuffers,esi
mov hSocket,ecx

mov eax,lpBuffers  ;取得数据包长度
mov eax,[eax]
mov dwPackSize,eax

mov eax,lpBuffers  ;取得数据包存放地址
mov eax,[eax+4h]
mov dwMemAdd,eax


invoke WriteFile,hPipe,dwMemAdd,dwPackSize,offset dwSize,NULL 

jmp [dwAddress]


  retn

_lanjie endp


End     DllEntry

这个代码在上次的代码基础上添加完成的,首先在DLL初始化的时候,加入
 invoke CreateThread,NULL,0,offset _Recv,NULL,NULL,addr dwRecvThreadID
这个进程被创建后,开始执行_Recv函数。

下面再来看一下发送参数的管道服务器端,服务器端在和客户端建立管道连接后,即启动线程开始利用循环不断向管道写入01字节,当发送数据按钮被点击时,即取出编辑框2的内容写入管道。源代码依然采用E语言编写

.版本 2
.支持库 EThread
.支持库 EInterProcess

.程序集 窗口程序集1
.程序集变量 管道句柄, 整数型


.子程序 __启动窗口_创建完毕




.子程序 _按钮1_被单击

启动线程 (&读取封包, )



.子程序 读取封包
.局部变量 数据封包, 字节集
.局部变量 数值, 整数型
.局部变量 连接, 逻辑型

管道句柄 = 创建命名管道 (“masm”)
连接 = 监听命名管道 (管道句柄)

.判断循环首 (读命名管道 (管道句柄, 数据封包))
    数值 = 取字节集长度 (数据封包)
    .如果真 (数值 > 0)
        编辑框1.加入文本 (查看字节集 (数据封包))
    .如果真结束


.判断循环尾 ()

返回 ()


.子程序 _按钮2_被单击

启动线程 (&发送封包, )



.子程序 发送封包
.局部变量 发送封包, 字节集
.局部变量 状态, 整数型
.局部变量 长度, 整数型

发送封包 = 到字节集 (编辑框2.内容)
长度 = 取字节集长度 (发送封包)

.判断循环首 (长度 = 0)      ;根据数据长度判断是否有数据将要发送
    写命名管道 (管道句柄, { 1 })  ;没有数据被发送,即开始循环发送01字节
.判断循环尾 ()


写命名管道 (管道句柄, 发送封包)    ;如果数据长度不为0,说明有数据需要发送,即可开始发送字节集数据

返回 ()

以上代码本人已经测试通过,不过没有加入错误处理的相关代码。



关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有