首页
社区
课程
招聘
控制其他程序内部函数-第二部分(汇编源代码)
发表于: 2006-6-4 19:00 8073

控制其他程序内部函数-第二部分(汇编源代码)

2006-6-4 19:00
8073

今天用了一天的时间在调试第二部分代码,本以为在昨天代码的基础上实现第二部分功能应该比较简单,没想到还是费了不少力气,呵呵。
    好了,还是先说下大体思路,如果需要调用其它进程的内部函数做自己的事情,那么必须先把需要调用的函数的参数传递给目标函数,要实现这个功能我还是选用管道通信技术,毕竟上一部分已经建立了一个管道。然后由我们的程序把参数利用管道发给已经插入到目标进程中的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,说明有数据需要发送,即可开始发送字节集数据

返回 ()

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


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (4)
雪    币: 196
活跃值: (135)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
2
支持一下,E语言...
2006-6-4 19:36
0
雪    币: 1852
活跃值: (504)
能力值: (RANK:1010 )
在线值:
发帖
回帖
粉丝
3
期待更多的佳作
2006-6-4 19:40
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
最初由 北极星2003 发布
期待更多的佳作

同感
2006-7-20 21:19
0
雪    币: 249
活跃值: (10)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
5
呵呵,E语言被认作 Visual C++ [overlay]
而且可移植性又不如其他高级语言
还是直接用VC写好一点
2006-7-23 11:25
0
游客
登录 | 注册 方可回帖
返回
//