原理
获取内存中代码段中需解密的片段,并解密。
实现
为了方便,使用xor进行加解密,并使用密钥为8。需要MASMPlus和W32Dasm。
第一个程序代码
这里的代码并没有加密,但却在运行时解密,因此会运行时错误。
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
include masm32.inc
include gdi32.inc
includelib gdi32.lib
includelib user32.lib
includelib kernel32.lib
includelib masm32.lib
include macro.asm
.data
lpMsg db "I can decrypt myself!",0
.data?
buffer db MAX_PATH dup(?)
.CODE
START:
mov edi,Virus_start
mov ecx,Virus_end
sub ecx,edi
mov eax,8
Decrypt:
xor [edi],eax
inc edi
loop Decrypt
Virus_start:
push offset lpMsg
call StdOut
;invoke StdOut,offset lpMsg
Virus_end:
invoke StdOut,offset lpMsg
invoke StdIn,addr buffer,sizeof buffer
invoke ExitProcess,0
end START
用W32Dasm反编译,需要被加密代码(反汇编略)为
:0040101F 6800304000
:00401024 E828000000
提取机器码:6800304000E828000000
获取加密后的内容
上一个C++写的程序来加密这段代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned char BYTE;
typedef unsigned int DWORD;
BYTE buff[2];
const BYTE key = 8;
BYTE value;
BYTE scan(BYTE buf[2]);
void print(BYTE x,FILE* f);
int main();
BYTE scan(BYTE buf[2])
{
BYTE tmp=0;
if(buf[0]>='0'&&buf[0]<='9') tmp=buf[0]-'0';
else tmp=buf[0]-'A'+10;
tmp=tmp*16;
if(buf[1]>='0'&&buf[1]<='9') tmp+=buf[1]-'0';
else tmp+=buf[1]-'A'+10;
return tmp;
}
void print(BYTE x,FILE* f)
{
fprintf(f,"\tdb ");
BYTE tmp[2];
tmp[0]=x/16;
tmp[1]=x%16;
if(tmp[0]>=0&&tmp[0]<=9) fprintf(f,"%c",tmp[0]+'0');
else fprintf(f,"%c",tmp[0]+'A'-10);
if(tmp[1]>=0&&tmp[1]<=9) fprintf(f,"%c",tmp[1]+'0');
else fprintf(f,"%c",tmp[1]+'A'-10);
fprintf(f,"h\n");
}
int main()
{
FILE* f=fopen("1.code","r");
FILE* n=fopen("1.decode","w");
while(fread(buff,1,2,f)!=0)
{
value=scan(buff);
value=value^key;
print(value,n);
}
}
把刚才的机器码写入1.code中,运行这个C++程序,在1.decode中得到
db 60h
db 08h
db 38h
db 48h
db 08h
db E0h
db 20h
db 08h
db 08h
db 08h
这是不符合Masm标准的,修改为
db 60h
db 08h
db 38h
db 48h
db 08h
db 0E0h
db 20h
db 08h
db 08h
db 08h
接着替换原来的汇编代码
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
include masm32.inc
include gdi32.inc
includelib gdi32.lib
includelib user32.lib
includelib kernel32.lib
includelib masm32.lib
include macro.asm
.data
lpMsg db "I can decrypt myself!",0
.data?
buffer db MAX_PATH dup(?)
.CODE
START:
mov edi,Virus_start
mov ecx,Virus_end
sub ecx,edi
mov eax,8
Decrypt:
xor [edi],eax
inc edi
loop Decrypt
Virus_start:
db 60h
db 08h
db 38h
db 48h
db 08h
db 0E0h
db 20h
db 08h
db 08h
db 08h
;invoke StdOut,offset lpMsg
Virus_end:
invoke StdOut,offset lpMsg
invoke StdIn,addr buffer,sizeof buffer
invoke ExitProcess,0
end START
修改工程属性
然而,Windows下代码段默认不可写,需要修改段属性。在链接参数后补上 /section:.text,rw 即可。
(可选)美化源代码
源代码有很多db,不好看,再次使用W32Dasm反编译,得到
:00401016 60 pushad
:00401017 0838 or byte ptr [eax], bh
:00401019 48 dec eax
:0040101A 08E0 or al, ah
:0040101C 2008 and byte ptr [eax], cl
:0040101E 0808 or byte ptr [eax], cl
用反编译代码替换源代码
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
include masm32.inc
include gdi32.inc
includelib gdi32.lib
includelib user32.lib
includelib kernel32.lib
includelib masm32.lib
include macro.asm
.data
lpMsg db "I can decrypt myself!",0
.data?
buffer db MAX_PATH dup(?)
.CODE
START:
mov edi,Virus_start
mov ecx,Virus_end
sub ecx,edi
mov eax,8
Decrypt:
xor [edi],eax
inc edi
loop Decrypt
Virus_start:
pushad
or byte ptr [eax], bh
dec eax
or al, ah
and byte ptr [eax], cl
or byte ptr [eax], cl
;invoke StdOut,offset lpMsg
Virus_end:
invoke StdOut,offset lpMsg
invoke StdIn,addr buffer,sizeof buffer
invoke ExitProcess,0
end START
然而,or al,ah 却编译成了0AC4,因此最终代码如下
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
include masm32.inc
include gdi32.inc
includelib gdi32.lib
includelib user32.lib
includelib kernel32.lib
includelib masm32.lib
include macro.asm
.data
lpMsg db "I can decrypt myself!",0
.data?
buffer db MAX_PATH dup(?)
.CODE
START:
mov edi,Virus_start
mov ecx,Virus_end
sub ecx,edi
mov eax,8
Decrypt:
xor [edi],eax
inc edi
loop Decrypt
Virus_start:
pushad
or byte ptr [eax], bh
dec eax
db 08h
db 0E0h
and byte ptr [eax], cl
or byte ptr [eax], cl
;invoke StdOut,offset lpMsg
Virus_end:
invoke StdOut,offset lpMsg
invoke StdIn,addr buffer,sizeof buffer
invoke ExitProcess,0
end START
运行结果