加壳

加壳

在这里插入图片描述

整个头部是以0x200粒度对齐的, 一般情况下,头部都有0x400字节的大小. 整个头部以区段头结尾. 然而区段头并没有完全占用剩下的所有空间, 往往都会有一些剩余的空间被0填充.当添加新的区段头的时候, 其实就是将新的区段头数据填入到这些剩余的填充空间中.
下面开始给你的程序开始增加内容,通过2种方法,
在这里插入图片描述
不管用什么方法,都需要先记录入口点,一会加区段的时候需要用,如果没记住,会有很大麻烦。
1.第一种方法用LordPE去增加区段。
​ 1.1先将自己想要添加的软件拽到LordPE里,注意查看一下LordPE的选项是否选到了打开PE编辑器
在这里插入图片描述
将文件拽如LordPE里,点击区段,右键选择添加区段
在这里插入图片描述
刚添加的区段里面什么内容都没有,需要自己设置一下,选到自己添加的区段,右键选择编辑区段,区段名字可以自己设计,虚拟大小,和物理大小也可以自己写,看写的壳大小。
在这里插入图片描述
设计完之后,再使用010Editor添加文件数据,打开010,选择到最底下,这个时候观察010,发现,现在的地址和新建的区段的偏移是不一样的,
在这里插入图片描述
这个时候,需要用0将剩下的填满,直到362800为止。
在这里插入图片描述
接下来,就是往新建的区段里填充数据了,
在这里插入图片描述
然后将新建区段的地址写在里面,大小就是当初创建时候的大小,下面要选到Hex,要不会不知道填到哪里。
在这里插入图片描述
添加完,保存即可。
1.2 修改OEP,增加OEP代码
原OEP:00147A7F
新OEP:0036E000
在这里插入图片描述
同时还学要修改一下软件的入口点,上面忘记说了,还需要修改一下区段数目。
在这里插入图片描述
然后添加代码,用x32dbg打开如软件,
在这里插入图片描述
进入到新创建的区段,进行编写代码,
在这里插入图片描述
call 第五个地址,E8占一个字节,00 00 00 00 占4个字节,减去一个RVA,前面用了5个字节,所以是36E005.
3.通过PEB.Ldr找到Kernel32.dll的加载地址的方法:
先找到peb的首地址,fs[0x30]保存的peb的首地址,fs:保存的线程环境块的首地址。
;mov eax , fs:[0x30] ; eax => peb首地址
找到Peb首地址之后,通过0xc 找到PEB.Ldr
在这里插入图片描述
获取_PEB_LDR_DATA结构体数据:
在这里插入图片描述
如图,0xc和0x1c都可以,在这里用0xc进行查找,
mov eax , [eax + 0ch]; eax => PEB.Ldr的值
mov eax , [eax + 0ch]; eax => PEB.Ldr的值
在这里插入图片描述
吧这个地址赋值给eax可以找到主模块。因为这个地址000的,
在这里插入图片描述
然后在吧这个地址赋值到eax就到了下一张表NTDLLmov eax , [eax] ;
eax =>_PEB_LDR_DATA.InLoadOrderMoudleList.Flink(NTDLL)
在这里插入图片描述
然后继续获取下一个,还是000的地方mov eax,[eax] ; _LDR_DATA_TABLE_ENTRY.InLoadOrderMoudleList.Flink(kernel32),
这个时候就到了我们要找的Kernel,dll
在这里插入图片描述
最后找到我们需要的DLLBase
mov eax,[eax+018h]; _LDR_DATA_TABLE_ENTRY.DllBase
0x75c9000位Kernel.dll模块的首地址
遍历导出表
; 1. dos头 --> nt头 --> 扩展头 --> 数据目录表
mov ebx , [eax+03ch]; eax=>偏移到NT头,ebx取地址,偏移
add ebx , eax ; ebx=>NT头的首地址 PE头
add ebx , 078h; ebx => 扩展头首地址
; 2. 得到导出表的RVA
mov ebx , [ebx];扩展头的第一个表的地址就是ebx
add ebx , eax; ebx ==> 导出表首地址(VA)

; 3. 遍历名称表找到GetProcAddress
; 3.1 找到名称表的首地址
lea ecx , [ebx+020h];
mov ecx , [ecx]; // ecx => 名称表的首地址(rva)
add ecx , eax; // ecx => 名称表的首地址(va)
xor edx , edx; // 作为index来使用.
; 3.2 遍历名称表
_WHILE:
​ mov esi , [ecx+edx*4] ; esi => 名称的rva
​ lea esi ,[esi + eax ] ; esi=>名称首地址
​ cmp dword ptr [esi],050746547h ;47657450 726F6341 64647265 7373
​ jne _LOOP
​ cmp dword ptr [esi+4],041636f72h
​ jne _LOOP
​ cmp dword ptr [esi+8],065726464h
​ jne _LOOP
​ cmp word ptr [esi+0ch],07373h
​ jne _LOOP
​ ; 找到之后
​ mov edi , [ebx+024h] ; edi => 名称的序号表的rva
​ add edi , eax ; edi => 名称的序号表的va

mov di , [edi+edx*2] ; 序号表是2字节的元素,因此是*2
					  ; edi保存的是GetProcAddress的在
					  ; 地址表中的下标
and edi,0FFFFh
; 得到地址表首地址
mov edx ,[ebx + 01ch] ; edx => 地址表的rva
add edx , eax ; edx => 地址表的va
mov edi , [edx + edi * 4]; edi => GetProcAddress的rva
add edi , eax ; ; edx => GetProcAddress的va
jmp _ENDWHILE

_LOOP:
​ inc edx ; // ++index
​ jmp _WHILE
_ENDWHILE:

xchg ebx,eax
; ebx => 加载基址
; edi => GetProcAddress地址
; 获取LoadLibrary
; GetProcAddress(ebx,“LoadLibraryA”);
​ call _NEXT
​ db “LoadLibraryA”,0
_NEXT:
​ push ebx
​ call edi ; 调用GetProcAddress
​ xchg esi , eax; esi => LoadLibraryA地址

; 加载user32.dll
; LoadLibraryA("user32.dll")
call _NEXT1
db "user32.dll",0

_NEXT1:
​ call esi ; eax => user32.dll的加载基址
​ ; 获取MessageBoxA
​ ; 调用GetProcAddress(eax,“MessageBoxA”);
​ call _NEXT2
​ db “MessageBoxA”,0
_NEXT2:
​ push eax; eax => user32.dll的加载基址
​ call edi ; eax => MessageBoxA地址
​ ; MessageBoxA(0,“大家好,我是一个壳”,“提示”,0);
​ push 0
​ call _NEXT3
​ db “提示”,0
_NEXT3:
​ call _NEXT4
​ db “大家好,我是一个壳”,0
_NEXT4:
​ push 0
​ call eax ; MessageBoxA
​ ; 跳转到OEP
​ mov eax, 0147A7Fh ; oep rva
​ add eax,0400000h ; 加载基址
​ jmp eax;
end main
end

猜你喜欢

转载自blog.csdn.net/dohxxx/article/details/85340414