首页
社区
课程
招聘
[讨论]有没有可能用VC编写一个EXE、DLL两用的可执行文件?
发表于: 2009-2-10 23:37 8652

[讨论]有没有可能用VC编写一个EXE、DLL两用的可执行文件?

2009-2-10 23:37
8652
会遇到的主要问题:
1、只要PE文件头正确,作为Exe运行不难,不过要做为DLL被LoadLibrary加载,那么重定位表是不可缺少的。
2、如果有可能实现,那么两者的入口点是相同的,应该要进行区分,看到底是调用WinMain还是DllMain。

对应的解决方法:
1、因为VC只会对DLL生成重定位表,手工生成重定位表又不太现实,所以项目上只好建DLL项目,生成一个扩展名为EXE的DLL,再用UE之类的二进制编辑器打开这个EXE,找到"PE\0\0",偏移18个字节,把0E 21修改为0F 01保存,那么这个DLL现在就是真正的EXE了,可以双击运行。
2、由于文件入口点是相同的,所以不能把入口函数写死,那么怎么判断这次进入入口函数是EXE调用还是DLL调用呢?
这里我定义了一个函数:
__declspec(naked) HMODULE WINAPI GetSelfModuleHandle()
{
	_asm
	{
		sub esp, 28
		mov eax, esp
		push 28
		push eax
		call label0
	label0:
		call dword ptr[VirtualQuery]
		test eax, eax
		jz label1
		mov eax, [esp + 4]
	label1:
		add esp, 28
		ret
	}
}

这个函数可以找到自身的HINSTANCE,也就是通常WinMain或者DllMain的第一个参数。
另外我们知道GetModuleHandle(NULL)会返回EXE的HINSTANCE,所以可以用这两者比较一下,如果GetModuleHandle(NULL)==GetSelfModuleHandle()为真说明是EXE调用,否则是DLL调用。
因此这样来构造入口函数:
//手动指明入口函数
#pragma comment(linker,"/entry:SmartMain") 
//声明一下通常意义上的EXE和DLL入口函数
extern "C" BOOL WINAPI _DllMainCRTStartup(HANDLE  hDllHandle, DWORD   dwReason, LPVOID  lpreserved);
#ifndef _UNICODE
extern "C" int WinMainCRTStartup(void);
#else
extern "C" int wWinMainCRTStartup(void);
#endif

extern "C" __declspec(naked) int WINAPI SmartMain(HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved)
{	//智能选择WinMain和DllMain去执行
	_asm
	{
		push ebx
		push 0
		call dword ptr[GetModuleHandle]
		mov ebx, eax
		call GetSelfModuleHandle
		cmp ebx, eax
		jnz label0
#ifndef _UNICODE
		call WinMainCRTStartup	;EXE情况下调用原来的EXE入口函数
#else
		call wWinMainCRTStartup	;EXE情况下调用原来的EXE入口函数
#endif
		pop ebx
		ret		;Exe执行的WinMain实际上没有调用参数,所以是ret而不是ret 12。
	label0:
		push dword ptr[esp + 16]
		push dword ptr[esp + 16]
		push dword ptr[esp + 16]
		call _DllMainCRTStartup	;DLL情况下调用原来的DLL入口函数
		pop ebx
		ret 12
	}
}


1、完成以上两点后,将项目属性修改为EXE项目,编译,运行正常;
2、修改回DLL项目,编译,用其他EXE加载之,运行也正常;
3、将此DLL用UE将0E 21修改0F 01保存(前面提到的类型标记),也就是改正真正的EXE,运行也正常;
4、将此EXE用其他EXE加载之,运行……,挂了 ,出错位置,调用某一个API的时候挂了,API对应的IAT表似乎没有生成,所以不能调API,一调就挂,不过原因不明 ,可以知道的是,这个EXE和第2步的DLL,仅仅是0F 01和0E 21这个标记的区别,其他都一样。

各位大侠认为此帖的标题是真命题还是假命题呢?我暂时没辙了……

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (13)
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
2
注意看此次奇虎360比赛的第四题
2009-2-10 23:44
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
3
我做那个题时的一个半成品应该符合你的要求,不过代码没了…
2009-2-10 23:46
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
不知道奇虎360有啥比赛?对了我这里说的这个Exe是可以通过正常手段被LoadLibrary的,而不是VirtualAlloc分配内存,再自己去做重定位的……
LS说说思路看看……
2009-2-10 23:49
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
5
做成DLL就可以了啊,只要有重定位表,当成DLL和EXE加载时都不会有什么问题,导入表也不用你处理,但是可能还是要改一个IMAGE_FILE_DLL标志。极端一点的方案,无导入表无重定位数据,更容易处理
2009-2-11 09:26
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
本来就是已经做成DLL了,只不过只要一修改类型标志为EXE,LoadLibrary加载后,运行就会失败,出错的地方在API调用;不修改当作DLL当然是问题,不过不管是双击,还是命令行,系统都会提示不是有效的WIN32应用程序。

原因是已经找到了,将EXE用LoadLibrary加载的话,IAT表不会帮你生成,EP入口函数也不会被调用。
根据MSDN的说法,他说将EXE用LoadLibrary加载的目的是取得其中的资源,而不是用来作代码执行。可能正是这个原因才没有做IAT表生成和入口函数调用,这样看来,这帖标题只能是假命题了……
2009-2-11 10:53
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
7
EXE用LoadLirary加载关键还在那个标志
2009-2-11 11:44
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
8
发觉LS都不看他人说话内容的……
2009-2-11 12:04
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
9
我看到标题进来的,看完内容也没想你非得要论证一下这个命题,可能我没说清楚,抱歉。我前面说了,你的方法是可行的,也给出了我的极端方案,但是LoadLiarary加载一个双击可正常运行的EXE文件时检查不到DLL标志就不会处理重定位表和导入表,仅仅是把文件映射到内存而已,更不会调用其入口函数,关键就在那个标志,这就是为什么360比赛的第四题作为DLL测试时要自行查找入口并调用。因此,你的命题是假的,一个正常可运行的的EXE不做任何修改直接用LoadLibrary作为DLL加载并运行是不行的。如果你认为我说的不对,请指正。
2009-2-11 14:14
0
雪    币: 2067
活跃值: (82)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
10
听说DLL没Export是不会被载入的
LZ可否将文件上传来看看.
2009-2-11 14:44
0
雪    币: 359
活跃值: (41)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
同意你的观点,只是你前面说的让人感觉似乎有其他解决方法似的。

其实我是在想有没有可能做一个单文件的全局消息钩子,临时释放文件的方法不算,钩子的目的还是DLL注入,再做APIHook。其实注入方法有很多,不一定要用消息钩子,不过我希望可以完美的退出并还原现场,这似乎只有消息钩子可以胜任了吧!?不过其他进程的消息钩子,只能是通过DLL来实现,虽然可以通过rundll32来调用DLL,不过用起来毕竟不方便。因为是注入,其他进程只会通过LoadLibrary这种传统的方式来加载,我们没有办法去做些小动作,来让它正常起来,可能这确实没有什么办法了吧。



传了份测试代码上来,VS2003编译的,直接F5是用rundll32加载dll。
对于已经生成的dll,把它扩展名改成EXE,用LordPE把PE文件头的特征值那一项21OE修改成010E就可以双击直接运行。(如果手头上没有LordPE,也可以用UE找到"PE\0\0",往后数18个字节,把21 0E修改成01 0E就行了,改一个字节)
上传的附件:
2009-2-12 10:45
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
12
原来是做单文件消息钩子?貌似见有人搞过,SetWindowsHookEx时把当前程序的hInstance传了进去。
2009-2-12 11:51
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
13
多个文件没什么大不了,需要的时候放出来就行了,跑路的时候还是一个
2009-2-12 11:53
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
14
现在驱动都白菜了,不如驱动中监控进程创建然后插DLL进去,消息钩子只对窗口程序有效啊
2009-2-12 11:57
0
游客
登录 | 注册 方可回帖
返回
//