我的壳概念

ekenchan 2003-08-21 05:20:38
我正在写一个类似壳的东西,原理是把宿主加到壳程序的尾部,运行时由壳程序调用VirtualAlloc函数分配内存,把宿主程序精确定位到这块内存里面,再用LoadLibrary和GetProcAddress函数对宿主程序的引入表一一填充,模拟实现PE Loader的功能,然后开一新的线程执行宿主程序。但是我发现对于没有窗口的程序我的壳就可以发挥作用,然而把壳加到窗口程序上的时候,运行时什么反应也没有,程序就结束了,连个出错的信息也没有。有哪一位高手可以指点一下为什么?有没有可能完美的模拟PE Loader的功能?
...全文
84 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
紫郢剑侠 2003-08-23
  • 打赏
  • 举报
回复
研究。。。
紫郢剑侠 2003-08-22
  • 打赏
  • 举报
回复
期待..
sazsa 2003-08-22
  • 打赏
  • 举报
回复
再学习
sh210 2003-08-22
  • 打赏
  • 举报
回复
学习
ekenchan 2003-08-22
  • 打赏
  • 举报
回复
我的壳运行宿主程序的关键代码

mov eax,PointerToOriginalFile
mov esi,eax ;esi、eax指向宿主文件
add eax,[eax + 3ch]
mov ebx,eax
mov edi,[eax + 34h] ;edi = 宿主文件的ImageBase
mov eax,[eax + 50h] ;eax = 宿主文件的ImageSize

push PAGE_EXECUTE_READWRITE
push MEM_COMMIT or MEM_RESERVE
push eax
push edi
call VirtualAlloc ;分配一块可读可写可执行的内存
cmp eax,edi
jne Quit ;出错处理

movzx ecx,word ptr [ebx + 6h] ;ecx=宿主文件Section的数目
push ecx ;保存一下
push edi ;同上
add ebx,sizeof IMAGE_NT_HEADERS ;ebx->宿主文件的第一个节表
mov ecx,[ebx + 14h] ;ecx=第一个节的文件偏移量,也即整个PE文件头的大小
shr ecx,2 ;ecx / 4
cld
rep movsd ;将PE文件头定位到相应的内存位置
pop edi ;Restore,指向内存块的基地址
pop ecx ;Section数目

;这时ebx指向第一个节表,下面的工作就是历遍所有的节表,装载各段到相应的内存位置
SegmentAlloc:
push ecx ;保存余下Section数目
mov ecx,[ebx + 10h] ;该段数据的原始大小
shr ecx,2 ;ecx / 4
push edi ;保存内存的基地址
add edi,[ebx + 0ch] ;[ebx + 0ch]是该段的RVA,加上基地址就是段的VA
rep movsd ;定位
pop edi ;Restore,指向基址
add ebx,sizeof IMAGE_SECTION_HEADER ;下一个节表
pop ecx ;Restore,Section数目
loop SegmentAlloc ;Section数目减一

mov ebx,edi ;ebx也指向基址
add edi,[edi + 3ch]
mov edi,[edi + 80h] ;取得IMAGE_IMPORT_DESCRIPTOR的RVA
add edi,ebx ;IMAGE_IMPORT_DESCRIPTOR的VA

xor ecx,ecx ;计数器清零,记录有多少个IMAGE_IMPORT_DESCRIPTOR结构,
;也就是要引入多少个DLLs
cld
ASSUME EDI:PTR IMAGE_IMPORT_DESCRIPTOR

;下面的工作就是填充引入表
NextDLL:
mov eax,[edi].Name1 ;取得DLL的文件名RVA
test eax,eax ;看看是不是到了最后一个IMAGE_IMPORT_DESCRIPTOR
jz DLLsLoaded ;是,则跳出大循环,说明所有DLLs已经载入
inc ecx ;计数,加一个DLL
push ecx ;save
add eax,ebx ;eax指向DLL的文件名
push eax
call LoadLibrary
mov ebp,eax ;ebp保存DLL的句柄
pop ecx ;Restore计数器
push eax ;在堆栈中保存DLL的句柄,留待释放
push ecx ;保存计数

push edi ;保存IMAGE_IMPORT_DESCRIPTOR指针
mov esi,[edi].OriginalFirstThunk
mov edi,[edi].FirstThunk
add esi,ebx ;取得IMAGE_THUNK_DATA数组的指针
add edi,ebx ;取得另一个IMAGE_THUNK_DATA数组的指针
;这个数组待会要填充函数地址
NextFunc:
mov eax,[esi] ;取得一个IMAGE_IMPORT_BY_NAME的RVA
test eax,eax ;看看是不是到了IMAGE_THUNK_DATA数组的末端
jz FunctionsFound ;是,则跳出小循环,说明所有函数地址已经找到
add eax,ebx ;IMAGE_IMPORT_BY_NAME的VA
inc eax
inc eax ;eax指向函数名
push eax ;save eax
push eax
@pushsz "ExitProcess"
call lstrcmp ;比较函数是不是ExitProcess()
test eax,eax
pop eax ;restore eax
jnz NotTargetFunc

@pushsz "ExitThread"
pop eax ;将ExitProcess替换成ExitThread

NotTargetFunc:
push eax
push ebp
call GetProcAddress
stosd ;填充地址

inc esi
inc esi
inc esi
inc esi ;esi指向IMAGE_THUNK_DATA数组的下一个元素
jmp NextFunc

FunctionsFound:
pop edi ;restore,IMAGE_IMPORT_DESCRIPTOR指针
pop ecx ;restore,计数器
add edi,SIZEOF IMAGE_IMPORT_DESCRIPTOR ;下一个IMAGE_IMPORT_DESCRIPTOR
jmp NextDLL

;至此填写引入表的工作完成,下面开创线程运行宿主程序
DLLsLoaded:
mov eax,ebx
add eax,[eax + 3ch]
mov eax,[eax + 28h]
add eax,ebx ;eax=宿主文件的Entry Point

push ecx ;保存引入的DLLs的数目,等一下要用到
xor ecx,ecx
push ecx
push ecx
push ecx
push eax
push ecx
push ecx
call CreateThread
test eax,eax
jz CannotRunOriginalFile ;出错处理

push INFINITE
push eax
call WaitForSingleObject ;挂起,等待宿主文件退出,跟着就是释放DLLs和内存,
;不再贴出
ekenchan 2003-08-21
  • 打赏
  • 举报
回复
回应楼上的:代码写得比较乱,等我加了注释再贴上来供大家批评指正。
NOV 2003-08-21
  • 打赏
  • 举报
回复
可以把代码放上来看看吗?
itaolu 2003-08-21
  • 打赏
  • 举报
回复
创建进程就不是壳了,呵呵。
做PE Loader很麻烦的一点就是资源的处理,M$并没有开放资源的具体资料,看着办吧。还有reloc节的东西也要一一进行重定位。
W32API 2003-08-21
  • 打赏
  • 举报
回复
你用创建进程的方式去调入你所说的宿主程序。。。该不会出现上面的问题。。。

21,458

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧