能力值:
( LV4,RANK:50 )
|
-
-
201 楼
开源就是硬道理.既然楼主这么慷慨.那一定不会反对附上注释吧.
这几天分析楼主的这个加壳程序.注释了一部分内容.
附上以帮助更多人读懂它.以后分析完后,再附上注释好的源码附件.注释的不一定对,请多指正.
程序太长,只能传上一小部分.
st1:
invoke VirtualProtect,addr entry,key_size,PAGE_READWRITE,addr temp1 ;改变内存页的保护属性
invoke GetTickCount
push eax
invoke GetTickCount
pop edx
mul edx
mov dword ptr dc_edit+1,eax ;用获得MS级的时间作为随机数
mov dword ptr ec_edit+1,eax
call calc_checksum ;制作两个代码的校验标志(0-所有代码中数据的字节和)
invoke GetTickCount
push eax
invoke GetTickCount
pop edx
mul edx
mov decode_key,eax ;用两个随机数相乘的值作为解码值.
not eax
mov rnd,eax
mov esi,offset _ok
mov edi,offset __ok
mov eax,decode_key
@@: ;把代码2编码,也就是加密
cmp esi,edi
jae @f ;JAE/JNB CF=0 时跳转
xor [esi],al
inc eax
ror eax,7 ;eax循环右移>>7
inc esi
jmp @b
@@:
invoke GetCommandLine
call trans ;分解命令行
invoke CreateFile,addr fname1,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0
cmp eax,INVALID_HANDLE_VALUE
je error1
mov hfile1,eax
invoke CreateFile,addr fname2,GENERIC_WRITE,0,0,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,0
cmp eax,INVALID_HANDLE_VALUE
je error3
mov hfile3,eax
invoke GetFileSize,hfile1,0
mov fsize1,eax
invoke VirtualAlloc,0,fsize1,MEM_COMMIT,PAGE_READWRITE
mov pt1,eax
invoke ReadFile,hfile1,pt1,fsize1,addr temp1,0
mov ebx,pt1
mov esi,[ebx+3ch] ;IMAGE_DOS_HEADER.e_lfanew
cmp flag_clear_boundimport,0
je @f
lea eax,[ebx+esi+0d0h] ;IMAGE_DIRECTORY_ENTRY_IAT.值为12
mov dword ptr [eax],0
mov dword ptr [eax+4],0 ;清空这个表
@@:
cmp flag_clear_load_config,0 ;IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,值为11
je @f
lea eax,[ebx+esi+0c8h] ;清空这个表(一般来说这两个表都不用.)
@@:
mov dword ptr [eax],0
mov dword ptr [eax+4],0
@@:
mov eax,[ebx+esi+34h] ;指向ImageBase地址(RVA)
mov image_base,eax
push esi
lea esi,[ebx+esi+78h] ;IMAGE_DIRECTORY_ENTRY_EXPORT,指向导出表
mov edi,offset rva_table ;DIRECTORY表
mov ecx,80h
call move_memory ;调整各个表
pop esi
cmp flag_add_section,0 ;标志
je @f
add word ptr [ebx+esi+6],1
@@:
mov eax,0
xchg eax,[ebx+esi+80h] ;IMAGE_DIRECTORY_ENTRY_IMPORT,指向导入表
mov iat_offs,eax ;保存IAT,然后清空IAT
mov eax,0
xchg eax,[ebx+esi+84h]
mov iat_size,eax
mov eax,0
xchg eax,[ebx+esi+0a0h] ;IMAGE_DIRECTORY_ENTRY_BASERELOC,指向重定位表
mov reloc_offs,eax ;同样保存后清空
mov eax,0
xchg eax,[ebx+esi+0a4h]
mov reloc_size,eax
lea edi,[esi+0f8h] ;第一个节表
movzx eax,word ptr [ebx+esi+6] ;保存节的数目
mov temp1,eax
st2:
dec temp1
jz st3
jmp @f
cmp dword ptr [ebx+edi+0ch],0 ;;;;;;
je st3
cmp dword ptr [ebx+edi+08h],0 ;;;;;;
je st3
@@:
jmp st24
mov eax,dword ptr [ebx+esi+0a8h]
cmp eax,0
je @f
add eax,dword ptr [ebx+esi+0ach]
cmp eax,dword ptr [ebx+edi+0ch]
jb @f
mov eax,dword ptr [ebx+edi+0ch]
add eax,dword ptr [ebx+edi+8]
cmp eax,dword ptr [ebx+esi+0a8h]
ja st25
@@:
mov eax,dword ptr [ebx+esi+88h]
cmp eax,0
je @f
add eax,dword ptr [ebx+esi+8ch]
cmp eax,dword ptr [ebx+edi+0ch]
jb @f
mov eax,dword ptr [ebx+edi+0ch]
add eax,dword ptr [ebx+edi+8]
cmp eax,dword ptr [ebx+esi+88h]
ja st25
@@:
mov eax,dword ptr [ebx+esi+0c0h]
cmp eax,0
je @f
add eax,dword ptr [ebx+esi+0c4h]
cmp eax,dword ptr [ebx+edi+0ch]
jb @f
mov eax,dword ptr [ebx+edi+0ch]
add eax,dword ptr [ebx+edi+8]
cmp eax,dword ptr [ebx+esi+0c0h]
ja st25
@@:
st24:
mov eax,[ebx+edi+8] ;VirtualSize 节区大小
cmp eax,[ebx+edi+10h] ;SizeOfRawData 判断是否超过了对齐粒度
jbe @f
mov eax,[ebx+edi+10h]
@@:
mov ecx,[ebx+edi+14h] ;PointerToRawData 在文件中的偏移
;;;;;;add ecx,ebx
mov edx,[ebx+edi+0ch] ;VirtualAddress 节区的RVA
sub ecx,edx ; ;节区的RVA对应的偏移量
invoke encode,edx,eax,ebx,ecx ;对内存中的IAMAGE编码(加密被加壳的程序)
st25:
add edi,28h ;跳到下一个节(对每一节即代码,数据,资源都加密)
jmp st2
st3: ;各节的加密已经完成了
push edi
lea eax,[esi+0f8h] ;重新计算节的数目(最后节的节尾-起始节的节头)/节长
sub edi,eax
mov edx,0
mov eax,edi
mov edi,28h
div edi
mov number_of_section,eax
pop edi
cmp flag_add_section,0 ;引入的标志
jne st6
mov eax,fsize1
sub eax,[ebx+edi+14h]
test eax,00000fffh
jz @f
add eax,1000h
@@:
and eax,0fffff000h
push eax
add eax,key_size
test eax,00000fffh
jz @f
add eax,1000h
@@:
and eax,0fffff000h
mov [ebx+edi+08h],eax
mov [ebx+edi+10h],eax
or dword ptr [ebx+edi+24h],0a0000020h ;mov dword ptr [ebx+edi+24h],0e0000040h
pop ecx
mov eax,[ebx+edi+0ch]
add eax,ecx
add eax,offset entry
sub eax,offset entry
xchg [ebx+esi+28h],eax
mov shell_eip,eax
jmp st7
st6:
mov eax,key_size ;代码长度
test eax,00000fffh ;测试是否对齐(1000h*n)
jz @f
add eax,1000h
@@:
and eax,0fffff000h
mov [ebx+edi+8],eax ;写入新节的内容
sub edi,28h
mov eax,[ebx+edi+0ch]
add eax,[ebx+edi+8]
test eax,00000fffh
je @f
add eax,1000h
@@:
and eax,0fffff000h ;计算位置
add edi,28h
mov [ebx+edi+0ch],eax ;VirtualAddress 节区的RVA地址
mov eax,key_size
test eax,00000fffh
jz @f
add eax,1000h
@@:
and eax,0fffff000h
mov [ebx+edi+10h],eax ;SizeOfRawData 在文件中对齐后的尺寸
mov eax,fsize1
test eax,00000fffh
je @f
add eax,1000h
@@:
and eax,0fffff000h
mov [ebx+edi+14h],eax ; PointerToRawData 在文件中的偏移
mov dword ptr [ebx+edi+24h],0e0000020h ;Characteristics 节的属性
mov eax,[ebx+edi+0ch]
add eax,offset entry
sub eax,offset entry
xchg [ebx+esi+28h],eax ;更改AddressOfEntryPoint
mov shell_eip,eax ;入口
st7:
mov eax,[ebx+edi+0ch] ;新节区的VirtualAddress 节区的RVA地址
add eax,[ebx+edi+8] ;VirtualSize 新节区的尺寸
test eax,00000fffh ;测试有没对齐
je @f
add eax,1000h
@@:
and eax,0fffff000h
mov [ebx+esi+50h],eax ;更改SizeOfImage 内存中整个PE映像尺寸
;所有的文件头中要修改的部分都修改了
mov eax,decode_key ;解码键
xor shell_eip,eax
lea esi,entry00
mov ecx,__ok - entry00
@@:
not byte ptr [esi] ;加密entry00(解码加到被加壳文件的代码)的代码
inc esi
loop @b
mov flag_reentry,0 ;flag_reentry=0表示已加密
invoke WriteFile,hfile3,pt1,fsize1,addr temp1,0 ;写到新文件中(不过还是原文件的大小)
cmp flag_add_section,0 ;标志
jne st75
mov eax,fsize1
sub eax,[ebx+edi+14h]
mov ecx,1000h
sub ecx,eax
jns st71
@@:
add ecx,1000h
js @b
st71:
mov eax,ecx
jmp st8
st75:
mov eax,fsize1 ;新文件的长度
test eax,00000fffh ;有无对齐
je @f
add eax,1000h
@@:
and eax,0fffff000h
sub eax,fsize1
st8:
lea ecx,_fill
invoke WriteFile,hfile3,ecx,eax,addr temp1,0 ;写入_fill处的数据.现在是空值(加大1K)
mov eax,key_size
test eax,00000fffh
jz @f
add eax,1000h
@@:
and eax,0fffff000h
invoke WriteFile,hfile3,addr entry,eax,addr temp1,0 ;写入entry代码
invoke CloseHandle,hfile1 ;关闭这两个文件
invoke CloseHandle,hfile3
invoke VirtualFree,pt1,0,MEM_RELEASE
invoke CreateFile,addr fname2,GENERIC_READ + GENERIC_WRITE,0,0,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0
cmp eax,INVALID_HANDLE_VALUE
je error3
mov hfile1,eax
invoke GetFileSize,hfile1,0 ;得到文件的大小,用于后面读出全部内容
mov fsize1,eax
invoke VirtualAlloc,0,fsize1,MEM_COMMIT,PAGE_READWRITE ;分配虚拟内存
mov pt1,eax
invoke ReadFile,hfile1,pt1,fsize1,addr temp1,0 ;把文件读入缓冲区pt1中
mov ecx,fsize1
mov edi,pt1
uu1:
cmp ecx,8 ;在文件中有无'LiNr'和'VoTa'字符串
jb nofound
cmp dword ptr [edi],'LiNr' ;'rNiL' ;加壳后的标志'rNiLaToV'
jne uu2
cmp dword ptr [edi+4],'VoTa' ;'aToV'
je found
uu2:
inc edi
loop uu1
jmp nofound
found: ;已加壳了
add edi,8
sub edi,pt1 ;获得标志'rNiLaToV'的偏移量
mov ebx,pt1
mov esi,[ebx+3ch] ;获得PE头位置
movzx ecx,word ptr [ebx+esi+6] ;扩展为双字NumberOfSections
mov eax,[ebx+esi+74h] ; NumberOfRvaAndSizes
shl eax,3 ;NumberOfRvaAndSizes*8(每个IMAGE_DATA_DIRECTORY 8字节)
lea edx,[ebx+esi+78h] ;IMAGE_DIRECTORY_ENTRY_EXPORT
add edx,eax ;得到节表的位置
uu3:
cmp dword ptr [edx+14h],edi ;PointerToRawData 在文件中的偏移
ja s_nt
mov eax,[edx+8] ;VirtualSize 节区的尺寸
add eax,[edx+14h] ;得到代码段的位置
cmp eax,edi
jbe s_nt ;超过的话,执行下面的代码
mov eax,edi ;文件尾
sub eax,[edx+14h] ;算出所余的空间
add eax,[edx+0ch] ;VirtualAddress 节区的RVA地址(把这个作为导入表的地址)
mov [ebx+esi+80h],eax ;IMAGE_DIRECTORY_ENTRY_IMPORT的VirtualAddress
mov dword ptr [ebx+esi+84h],14h ;IMAGE_DIRECTORY_ENTRY_IMPORT的isize(数据块的长度)
lea ecx,[eax+size1] ;
mov [ebx+edi+0ch],ecx ;VirtualAddress 节区的RVA地址
lea ecx,[eax+size1+size2] ;加上DLL的长度后的RVA
mov [ebx+edi+size1+size2+size3],ecx ;在原来的函数表后面再填上这个RVA
lea ecx,[eax+size1+size2+size3] ;算出新的RVA
mov [ebx+edi+10h],ecx ;SizeOfRawData 在文件中对齐后的尺寸
jmp found1
s_nt:
add edx,28h ;没超过的话,取下个节
loop uu3
jmp nofound
found1:
invoke SetFilePointer,hfile1,0,0,FILE_BEGIN
invoke WriteFile,hfile1,pt1,fsize1,addr temp1,0 ;重写,更改了IAT了.原来全是0
nofound:
invoke CloseHandle,hfile1 ;关闭原文件
invoke VirtualFree,pt1,0,MEM_RELEASE ;释放分配的内存
error1:
error2:
error3:
exit0:
invoke ExitProcess,0 ;退出进程,程序终止
_fill db 1000h dup (0) ;填充数据0
end start
|