其中,附加代码必须放在起始位置,程序运行时就执行它。被加壳程序和密码信息位置可以互换,我们只要知道它们的大小和准确位置就可以了。密码验证正确后,就把被加壳程序进行脱壳分离出来并执行它,等待它执行完毕,主进程才结束。
1.1附加代码的处理流程
在附加代码执行后,首先读取自身密码信息(包括附加的外壳程序长度、被加壳程序长度、密码等),同用户输入的密码进行比对,确认无误后,将被加壳程序脱壳分离出来,同时把自身隐藏起来,创建被加壳程序的进程,等待被加壳程序进程结束后,退出本应用程序。如果密码比对不成功,则直接退出。
1.2加壳处理流程
首先读取附加代码、被加壳程序文件名及路径,同时读取自己定义的信息结构和用户输入的密码(其实就是一个纪录)。创建一个内存流,将附加代码读入内存流中,定位在内存流尾端,再创建另外一内存流,将被加壳程序写入内存流。将被加壳程序的内存流拷贝在附加代码后面。最后将自定义的信息写入内存流,保存在临时文件中。删除被加壳的文件,将临时文件命名为被加壳程序的文件名。
1.3脱壳处理流程
脱壳的处理流程同加壳处理流程恰好相反。它首先创建一个内存流,将已经加壳的文件读入内存流,内存流定位到密码信息部分,验证密码信息,如果比对不成功,则退出程序。如比对成功后,内存流定位到被加壳程序部分,将它拷贝给另外一个内存流并保存为一个临时文件,删除已加壳的文件,将临时文件保存为被加壳程序的文件名,完成脱壳处理。
3. 程序的实现及解读
要实现程序的加壳脱壳处理,需要编写两个程序,即外壳程序(即附加代码)和加壳程序。外壳程序主要供加壳程序使用。其主要功能是提供用户输入密码,并比对已经加壳程序中密码信息同用户输入的密码是否相同。如果不同,则退出。比对成功,则进行脱壳处理,并运行脱壳后的程序。加壳程序用来将附加代码和密码信息附加到被加壳程序上。被加壳后的程序需要输入正确密码才能运行。
在这里,只列出加壳脱壳程序的关键代码。
3.1相关定义:密码信息和读取文件长度函数
为方便内存流的准确定位,必须知道文件的长度大小。其函数为:
function GetFilelen(filename:string):integer;
var
sr:TSearchRec;
begin
if (findfirst(filename,faAnyfile and not faDirectory,sr)<>0) then result:=0
else result:=sr.size;
findclose(sr);
end;
密码信息为一纪录结构,其原型为
Const
Flag='我的加密文件';
PassSize=15;//密码信息最高字符数
type
Tinfo=Record
Flag:string[Length(Flag)];// 加壳标志,由用户自定义
Name: ShortString;// 文件名
PassWord:string[PassSize];// 密码
ShellLen,SourceLen:integer;//附加代码长度和被加壳程序长度
end;
其实在密码信息部分,可任意添加自己的敏感信息。
3.2加壳程序
var
CodeName,myname: string;// 附加代码的文件名和临时文件名
myInfo: TInfo;
MsStream,SourceMem:TMemoryStream;//内存流
begin
CodeName:= ExtractFilePath(paramstr(0))+'shellprj.exe'; //附加代码的文件名
with myInfo do
begin
Flag := Flag;//自定义的标志
Name := ExtractFileName(SourceName);//文件名
Password := Edit2.Text;//密码
ShellLen := GetFilelen(CodeName);//附加代码的长度
SourceLen:=GetFilelen(SourceName);//被加壳程序长度
end;