加壳
整个头部是以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