首页
社区
课程
招聘
[求助]调用EXE中的函数......
发表于: 2010-6-13 12:01 17801

[求助]调用EXE中的函数......

2010-6-13 12:01
17801
我做了个EXE程序,内有很多可导出的函数。该EXE单独运行没有问题,所有函数都能正确执行。
  但是
  将它做为DLL看待时,在其它的EXE中LoadLibrary(....,'XXXX.EXE'),可以获得它的句柄,也能得到函数的地址,但确不能运行导出函数。调试时因其是EXE结构,调试器OD不能将它做为DLL看待,没法进行调试,谁有这方面的经验请出手相助。
谢谢!

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (29)
雪    币: 254
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
重定位信息 。。。。。。。。。。
2010-6-13 14:13
0
雪    币: 6
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
改他PE头....
2010-6-13 14:55
0
雪    币: 253
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
楼上各位,本人愚钝,能否详细指点?
2010-6-13 15:19
0
雪    币: 251
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
1. exe一般是没重定位信息的, 这种情况你必须保留他使用的地址给他用, 否则会异常
2. exe作为dll 加载进去, 很多东西是没经过初始化的(全局对象, crt库初始化 ....)

修改另外那个exe的基址 再编译 试试看
2010-6-13 15:40
0
雪    币: 364
活跃值: (91)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
给LZ推荐一个贴子http://bbs.pediy.com/showthread.php?t=113450 如果解决了你的问题,请帮他顶一下!!呵呵。
2010-6-13 16:40
0
雪    币: 253
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
5楼说的对,EXE做为DLL使用时,代码没有初始化,因此,当函数中如果只是简单的运算则可以被外部过程正常调用,而在函数中使用系统的API或资源时,则会因没有重定位信息不能正常运行。
  这正是我询求大家解决的问题
2010-6-13 21:48
0
雪    币: 253
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
借用6楼提供帖子中的论述方法,对我的问题重新描述:
    程序HH.EXE可独立运行,内有很多导出函数。
    程序CC.EXE也可独立运行。我希望CC可以使用HH的导出函数。
    但是HH做为DLL使用时,由于它是EXE文件,因此我没有办法将它象对待其它DLL程序那样正确初始化。
说的更具体一些就是EXE文件做DLL使用时如何对它做初始化

   请高人想想办法!此问题很有挑战性!!!
2010-6-14 08:11
0
雪    币: 208
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
exe的入口函数书WinMain,
DLL的的入口函数是DllMain
你在HH.EXE中增加一个DllMian函数来做初始化工作。
不知道这样行不行。
2010-6-14 08:44
0
雪    币: 517
活跃值: (84)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
10
在贴子http://bbs.pediy.com/showthread.php?t=113450的基础上,
修改后CC的一些导入库可能存在一些问题,会出现无法加载的情况。而且内部如果使用了HH的硬地址等,就无法独立运行了。
如果你需要做初始化,建议你在修改PE入口时,LoadLibrary前,先调用初始化代码,或许可以解决你的问题。
修改后可以使用API及系统资源,至于能不能使用窗口函数什么的,不大确定。
只不过调用的初始化代码不能是原先的入口了,而且现在IDE做出来的EXE,入口代码都是由编译器生成的,也的确做了一堆环境初始化工作,再调用main函数。结束后释放资源,调用ExitProcess。
既然CC、HH是你自己做的,那不如就把代码改造成DLL重新编译一遍呗,何必自找麻烦哩。初始化的确是件麻烦事。。。
2010-6-14 09:24
0
雪    币: 253
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
To iicup :
   按你的方法做了,可能是我实现的过程不对,没有成功。
To triones :
  CC、HH是自己做的,但我想让它们相互依存,如果它们之间少了另一半则功能上也会少很多。想有“1+1>2”的效果。如果做成公共DLL则没有相互依存的关系,功能上也固定了,只能是"1+1=2"
2010-6-14 10:04
0
雪    币: 517
活跃值: (84)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
12
那不如就做成plugin.dll喽
2010-6-14 11:08
0
雪    币: 253
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
有这面的目的,但plugin.dll是DLL,它必须依附与其它的EXE或DLL。
我希望HH.exe和CC.exe本身相对独立的,能够完成各自的功能。如果它们在一起时,就都具有plugin.dll作用,互为补充。
这只是设计上的想法,真的有点BT
2010-6-14 17:12
0
雪    币: 517
活跃值: (84)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
14
要不就让它们分别独立运行,然后开放通讯,依靠通讯完成相互功能。
否则,两个EXE之间的相互利用,难。
2010-6-15 11:42
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
15
这个原理还是很简单的,把目标exe可以随便加载,比如读文件,或者干脆LoadLibrary就可以了。然后搜索其导入表,都修改成正确的指针就行了。然后再修改exe内需要重定位的地址,这个也不麻烦的。

修正重定位表的代码大概如下:

        hMod = LoadLibrary("aa.exe");

        if (!hMod)
                return false;

        pDosHeader = (PIMAGE_DOS_HEADER)hMod;
        pNTHeaders = (PIMAGE_NT_HEADERS)((BYTE *)hMod + pDosHeader->e_lfanew);
        pOptHeader = (PIMAGE_OPTIONAL_HEADER)&(pNTHeaders->OptionalHeader);

        pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((BYTE *)hMod + pOptHeader->DataDirectory[1].VirtualAddress);

        bRet = TRUE;

        while(pImportDescriptor->FirstThunk)
        {
                //获取dll名称
                char * dllname = (char *)((BYTE *)hMod + pImportDescriptor->Name);

                pThunkData = (PIMAGE_THUNK_DATA)((BYTE *)hMod + pImportDescriptor->OriginalFirstThunk);

                int no = 1;
                while(pThunkData->u1.Function)
                {
                        if ((pThunkData->u1.Ordinal &  IMAGE_ORDINAL_FLAG) != IMAGE_ORDINAL_FLAG)
                        {
                                //获取函数名称
                                funname = (char *)((BYTE *)hMod + (DWORD)pThunkData->u1.AddressOfData + 2);
                                if (!GetModuleHandle(dllname))
                                {
                                        LoadLibrary(dllname);
                                }
                                myaddr = (int*)GetProcAddress(GetModuleHandle(dllname), funname);
                        }

                        PDWORD lpAddr = (DWORD *)((BYTE *)hMod + (DWORD)pImportDescriptor->FirstThunk) +(no-1);

                        MEMORY_BASIC_INFORMATION  mbi;
                        VirtualQuery(lpAddr,&mbi,sizeof(mbi));
                        VirtualProtect(lpAddr,sizeof(DWORD),PAGE_READWRITE,&dwOLD);

                        if (WriteProcessMemory(GetCurrentProcess(), lpAddr, &myaddr, sizeof(DWORD), NULL) == FALSE)
                        {
                                bRet = FALSE;
                                break;
                        }

                        VirtualProtect(lpAddr,sizeof(DWORD),dwOLD,0);

                        no++;
                        pThunkData++;
                }

                pImportDescriptor++;
        }

修正需要重定位的地址和数据:

        for (int i = 0; i < xxx; i++)
        {
                lpAddr = (PDWORD)(RelocAll[i] + (DWORD)hMod);

                VirtualQuery(lpAddr,&mbi,sizeof(mbi));
                VirtualProtect(lpAddr,sizeof(DWORD),PAGE_READWRITE,&dwOLD);

                ReadProcessMemory(hProcess, (LPCVOID)lpAddr, &dwOrg, sizeof(DWORD), &dwRetCount);

                dwOrg = dwOrg - 0x400000;
                dwOrg = dwOrg + (DWORD)hMod;

                if (WriteProcessMemory(hProcess, (void*)lpAddr, &dwOrg, sizeof(DWORD), NULL) == 0)
                        bRet = false;
        }
2010-6-15 13:58
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
16
我在这个帖子里发的附件,就是一个exe加载另外一个exe,然后直接在自己镜像内把那个exe跑起来了,不过被人说成简单一毛的东西,我也懒得说什么了。

http://bbs.pediy.com/showthread.php?t=99799
2010-6-15 14:06
0
雪    币: 2242
活跃值: (488)
能力值: ( LV9,RANK:200 )
在线值:
发帖
回帖
粉丝
17
这个exe是自己的,那么编译的时候生成重定位目录不就ok了吗
2010-6-15 14:13
0
雪    币: 223
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
rst
18
不光是重定位的问题,还有DLL初始化的问题

EXE和DLL的初始化代码都是由编译器加进去的
2010-6-15 20:30
0
雪    币: 253
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
非常感谢大家的回复!
To nbw  :
    看了你的代码,我想后面这段用于修改EXE导出表的,这种修改是否是在内存中进行的?如果是这样那它就是动态修改了。其基址0x400000可视具体情况进行改变,基址的确定是否需根据主调程序的基址确定还是根据做为DLL使用的EXE的基址确定?
    你的思路我理解为,HH.exe做为HH.dll使用时,需在 LoadLibrary("HH.exe");后修改重定位表,然后再取各导出函数的地址或名柄,最后调用。不知这样理解对不??
2010-6-17 07:46
0
雪    币: 253
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
To 16楼
    如果在一个CC.exe中让另一个HH.exe运行起来是一回事,而让CC.exe使用HH.exe中的函数则是另一回事。
可能是网友理解的产一样。
2010-6-17 07:52
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
21
第一句话问的那三个问号太长了,我看不过来,也不知道对不对。第二个句子理解的是对的。修改导入表这个很简单的。麻烦的是处理需要重定位的别的一些地址,比如hh.exe里原来可能有个这:

push 0x401234,而这个0x401234地方指向一个字符串。这时候你就要修正这个立即数了,让他指向正确的内存位置,这个就有点麻烦了。
2010-6-17 21:43
0
雪    币: 253
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
是这样?......。那么在HH.exe中就少用或不用立即数,非用不可的地方用常量。这查以在程序设计中达到。不知其它的地方还有那些需要注意的?

重复20楼的内容:  修改EXE导出表是在 LoadLibrary("HH.exe")后之后进行,也就是调入内存后进行修改?  如果是这样那它就是动态修改了。
  修改时,其基址0x400000可视具体情况进行改变,基址的确定是根据主调程序的基址确定还是根据做为DLL使用的EXE的基址确定?
2010-6-18 07:46
0
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
23
当然是根据做为DLL使用的EXE的基址确定。不好意思很绕口的问题我一般大脑自动过滤很严重
2010-6-18 09:15
0
雪    币: 253
活跃值: (89)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
To nbw:
谢谢你的帮助!
    也谢谢大家!的支持.
由于最近有点忙,对这个问题的深入学习和研究可能要待很长时间.慢慢学习,慢慢提高!
2010-6-21 07:54
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
25
与LZ握个手,之前也这么想过,用VS2003编写,不过当时觉得手工初始化dll太麻烦了,后来就扔到一边了。
当时弄出来的结果就是同一个文件,用LordPE打开修改特征值为010E就是exe,修改为210F就是dll。不过由于exe和dll的原始入口原型不同,还需要进行一些处理。exe的是int WinMainCRTStartup(void),dll的是BOOL WINAPI _DllMainCRTStartup(HANDLE, DWORD, LPVOID),如果要两者共存于一个文件,可以自己指定程序入口,用VirtualQuery取自身模块基址和GetModuleHandle取exe基址判断是否相等来确定当前是exe还是dll,然后再调用相应的原始入口并小心平衡堆栈即可,此外C/C++运行库要选择MD方式,否则wincrt0.obj和dllcrt0.obj有部分函数冲突,貌似无法解决。
2010-6-21 15:03
0
游客
登录 | 注册 方可回帖
返回
//