标题:自修改算法设计与实现
作者:壹只老虎
日期:2007-08-01
说明:转载请注明出处和保持文件完整性。
1:什么是自修改(个人定义的!嘿嘿!)
就是程序执行的时候,某段代码可以根据某些数据(比如密钥)自行修改。
2:特点
这种算法不同于一般的算法,一般算法的代码是静态的,人家可以打印出来慢慢分析,而这种算法在代码中保存的是加密过的代码,没有真正的密钥,是不可能解密出正确地执行代码的。
简单点说,算法等效于=>
If 注册码=不告诉你 then
注册成功;
3:优点
反汇编代码中保存的是加密后的代码,正确的代码不可见。
4:缺点
密钥一旦泄漏,本算法的失去意义。为了弥补这个缺点,请务必注意注册算法的强度。
5:应用
功能限制,注册算法等。
6:实现思路
第一:对于被加密的程序自身而言,需要有解密被加密的代码的功能,在被加密程序中,需要设置代码开始加密偏移和结束偏移两个标记。
第二:被加密程序根据输入的信息计算出一个解密密钥,进行代码的解密。(如果密钥和加密代码使用的密钥不同,那么不可能解密出正确的代码)。
第三:需要一个加密程序,用来加密待加密程序中的指定数据,我们需要给加密程序提供开始加密偏移和结束加密偏移,以及密钥。
第四:由于我们编写的代码经编译器编译后保存于代码段,但是代码段的段属性默认是读权限和可执行权限,我们的程序解密的时候需要将解密的代码写入代码段,所以,
我们需要修改被加密程序的代码短的段属性为:读+写+可执行权限。
第五:为了防止程序运行错误的解密后的代码的时候异常,所以我们需要对异常进行处理。
第六:在被加密程序中,为了方便寻找要加密的代码,我们需设置一个开始标记和结束标记,我设置的为:$40484048,即inc eax;dec eax;inc eax;dec eax;当然也可以设置为:$909090909090,即nop; nop; nop; nop; nop; nop;被加密程序编译完成后,用C32ASM以16进制方式打开它,搜索16进制40484048即可定位到编译后的待加密代码开始偏移和结束偏移。
7:如何破解(个人观点,欢迎大家讨论)
a:未知密钥,编程实现代码解密,程序自动判断解密后的代码是否正确。(难度比较大)
b:已知密钥,和普通的算法破解思路相同,因为程序会解密出正确的算法。
8:CrackMe01_Delphi源代码
{CrackMe01_DelphiReg.pas}
unit CrackMe01_DelphiReg;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, WinSkinData, jpeg, ExtCtrls,StrUtils;
type
TForm1 = class(TForm)
SkinData1: TSkinData;
Label1: TLabel;
Label2: TLabel;
edRegName: TEdit;
edRegCode: TEdit;
btnReg: TButton;
btnAbout: TButton;
btnExit: TButton;
Image1: TImage;
Label3: TLabel;
edRandom: TEdit;
procedure btnAboutClick(Sender: TObject);
procedure btnExitClick(Sender: TObject);
procedure btnRegClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const
KeyTitle = '壹只老虎CrackMe01_Delphi';
var
Form1: TForm1;
implementation
{$R *.dfm}
{十六进值字符串转换成LongInt值}
function HexStrToInt(S: String): LongInt;
var
i:Integer;
begin
Result := 0;
for i := 1 to Length(S) do
begin
if S[i] in ['0'..'9'] then
Result := Result * 16 + (Integer(S[i]) - 48)
else if S[I] in ['A'..'F'] then
Result := Result * 16 + (Ord(S[i]) - 55);
end;
end;
{注册按钮事件处理过程}
procedure TForm1.btnRegClick(Sender: TObject);
var
i,num:integer;
key:integer; {密钥}
code,name:string;
Label begindecrypt,enddecrypt,s0;
begin
name:=edRegName.Text; {取得注册名}
code:=edRegCode.Text; {取得注册码}
num:=strToint(edRandom.Text); {取得随机数}
try
key:=num xor HexStrToInt(LeftStr(code,8)); {根据注册码和随机数计算密钥}
except
Close;
end;
{解密代码}
asm
mov ebx,offset begindecrypt {开始解密偏移}
mov eax,offset enddecrypt {结束解密偏移}
sub eax,ebx {计算解密数据大小}
mov edx,0
mov ecx,4
div ecx
mov ecx,eax {ecx=解密数据大小 div 4}
mov esi,ebx {esi=开始解密偏移}
s0:{解密循环,每次处理一个dword}
mov eax,[esi]
xor eax,key
mov [esi],eax
add esi,4
loop s0
end;
{采用异常处理设计}
try
{为方便寻找开始解密标记编写的代码,对应16进制为:$40484048}
asm
inc eax;
dec eax;
inc eax;
dec eax;
end;
begindecrypt: {注册算法的开始标记}
num:=0;
if length(name)<6 then
begin
Application.MessageBox('Name is Too Short','no!no!no!',MB_ICONINFORMATION+MB_OK);
Close;
end;
for i:=1 to length(name) do
num:=num+i*ord(name[i]);
try
num:=num-StrToInt(RightStr(code,6));
if num=0 then
Application.MessageBox('Good Job!','heihei',MB_ICONINFORMATION+MB_OK)
else
Application.MessageBox('it is too false!','no!no!no!',MB_ICONINFORMATION+MB_OK);
Close;
except
Close;
end;
{保留4字节,用来填充注册算法长度<>4得倍数的长度}
asm
nop
nop
nop
nop
end;
enddecrypt: {注册算法的结束始标记}
{为方便寻找结束解密标记编写的代码,对应16进制为:$40484048}
asm
inc eax;
dec eax;
inc eax;
dec eax;
end;
except
{代码解密错误,则会异常退出}
Close;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.Title:=KeyTitle;
Form1.Caption:=KeyTitle;
Randomize;
{产生随机数显示}
edRandom.Text:=inttostr(Random(80000000)+12345678);
end;
procedure TForm1.btnAboutClick(Sender: TObject);
begin
Application.MessageBox(' 本CrackMe由 壹只老虎 制作! '+#13#10+#13#10+
' Email:tiger..tiger@163.com'+#13#10+#13#10+
' 2007-08-01','关于',MB_ICONINFORMATION+MB_OK);
end;
procedure TForm1.btnExitClick(Sender: TObject);
begin
Close;
end;
end.
9:加密工具源代码(我这里只是个半自动的加密工具,回头写个全自动的)
unit EncryptCodeSource;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, WinSkinData, jpeg, ExtCtrls;
type
TForm1 = class(TForm)
SkinData1: TSkinData;
Label1: TLabel;
edKey: TEdit;
btnEncrypt: TButton;
btnAttrib: TButton;
btnExit: TButton;
Image1: TImage;
Label3: TLabel;
edFilePath: TEdit;
btnView: TButton;
Label2: TLabel;
edStartAddress: TEdit;
edEndAddress: TEdit;
Label4: TLabel;
ofd: TOpenDialog;
procedure btnAttribClick(Sender: TObject);
procedure btnExitClick(Sender: TObject);
procedure btnEncryptClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure btnViewClick(Sender: TObject);
procedure edStartAddressKeyPress(Sender: TObject; var Key: Char);
procedure edEndAddressKeyPress(Sender: TObject; var Key: Char);
procedure edKeyKeyPress(Sender: TObject; var Key: Char);
private
{ Private declarations }
public
{ Public declarations }
end;
const
KeyTitle = '壹只老虎代码加密工具';
var
Form1: TForm1;
implementation
{$R *.dfm}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//> 函数说明:十六进值字符串转换成LongInt值
//> Made by:壹只老虎
//> 日 期:2007-8-1
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
function HexStrToInt(S: String): LongInt;
var
i: Integer;
begin
Result := 0;
for i := 1 to Length(S) do
begin
if S[i] in ['0'..'9'] then
Result := Result * 16 + (Integer(S[i]) - 48)
else if S[I] in ['A'..'F'] then
Result := Result * 16 + (Ord(S[i]) - 55);
end;
end;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//> 函数说明:获取文件大小
//> Made by:壹只老虎
//> 日 期:2007-8-1
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
function GetFileSize(const FileName: string): LongInt;
var
SearchRec: TSearchRec;
begin
try
if FindFirst(ExpandFileName(FileName), faAnyFile, SearchRec) = 0 then
Result := SearchRec.Size
else
Result := -1;
finally
FindClose(SearchRec);
end;
end;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//> 函数说明:设置strFileName文件的CODE段的属性为;读+写+可执行
//> Made by:壹只老虎
//> 日 期:2007-8-1
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
function SetSectionAttrib(strFileName:string):Boolean;
var
dwBuffer:DWORD; {文件读取缓冲区}
pe_header:IMAGE_NT_HEADERS; {PE文件头指针}
iNumberOfSections:Integer; {保存区块数目}
dwSecTableBase:DWORD; {保存区块头文件首址}
dwPEHeaderBase:DWORD; {保存PE文件头文件首址}
iLoop:Integer; {循环变量}
pSectionTable:IMAGE_SECTION_HEADER;{保存各区块表指针}
dwSectionAttrib:DWORD; {保存段属性}
fsWrite:TFileStream; {写文件文件流}
begin
{以读写方式建立文件流}
fsWrite:=TFileStream.Create(strFileName,fmOpenReadWrite);
{文件流指针移动到新EXE头部字段}
fsWrite.Seek($3C,soFromBeginning);
dwBuffer:=0;
{读取PE文件头文件地址}
fsWrite.ReadBuffer(dwBuffer,4);
dwPEHeaderBase:=dwBuffer;
{文件指针指向PE 文件头}
fsWrite.Seek(dwBuffer,soFromBeginning);
{读入pe文件头到内存}
fsWrite.ReadBuffer(pe_header,SizeOf(IMAGE_NT_HEADERS));
{取区块数目}
iNumberOfSections:=pe_header.FileHeader.NumberOfSections;
{获取区块表头文件地址:}
dwSecTableBase:=dwPEHeaderBase+SizeOf(IMAGE_NT_HEADERS);
{分别读取各个区块的信息到内存}
for iLoop:=0 to iNumberOfSections-1 do
begin
{文件指针指向第iLoop区块表}
fsWrite.Seek(dwSecTableBase,soFromBeginning);
{读入区块表信息}
fsWrite.ReadBuffer(pSectionTable,SizeOf(IMAGE_SECTION_HEADER));
{读取区块数据文件地址}
if LPCSTR(@pSectionTable.Name[0])='CODE' then
begin
fsWrite.Seek(dwSecTableBase+36,soFromBeginning);
dwSectionAttrib:=$E0000020;
fsWrite.WriteBuffer(dwSectionAttrib,SizeOf(DWORD));
fsWrite.Free;
break;
end;
{文件指针移动}
dwSecTableBase:=dwSecTableBase+SizeOf(IMAGE_SECTION_HEADER);
end;
Result:=True;
end;
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//> 函数说明:数据加密过程
//> Made by:壹只老虎
//> 日 期:2007-8-1
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
procedure TForm1.btnEncryptClick(Sender: TObject);
var
iKey:integer;
fsWrite:TFileStream;
iStartAddress,iEndAddress,iDataSize:Integer;
bBuffer:array[0..1024*400]of byte; {待加密数据存储缓冲区}
pBuffer:Pointer;
Label s0;
begin
{打开文件}
iStartAddress:=HexStrToInt(edStartAddress.text); {取开始加密偏移}
iEndAddress:=HexStrToInt(edEndAddress.text); {取结束加密偏移}
iKey:=StrToInt(edKey.text); {取密钥}
iDataSize:= iEndAddress-iStartAddress; {取加密数据大小}
if iStartAddress>=iEndAddress-3 then
begin
Showmessage('结束地址必须>=开始地址+4');
exit;
end;
if iEndAddress>GetFileSize(edFilePath.Text)then
begin
Showmessage('结束地址不能大于文件大小');
exit;
end;
if iKey<100 then
begin
Showmessage('密钥至少为3位');
exit;
end;
fsWrite:=TFileStream.Create(edFilePath.Text,fmOpenReadWrite);
fsWrite.Seek(iStartAddress,soFromBeginning);
iDataSize:=(iDataSize div 4)*4;
fsWrite.ReadBuffer(bBuffer,iDataSize);
pBuffer:=@bBuffer;
{解密代码}
asm
pushad
mov eax,iDataSize
mov edx,0
mov ecx,4
div ecx
mov ecx,eax
mov esi,0
s0:
mov ebx,[pBuffer]
mov eax,[ebx];
xor eax,iKey
mov [ebx],eax
add pBuffer,4
loop s0
popad
end;
fsWrite.Seek(iStartAddress,soFromBeginning);
fsWrite.WriteBuffer(bBuffer,iDataSize);
fsWrite.Free;
showmessage('代码加密完成');
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Application.Title:=KeyTitle;
Form1.Caption:=KeyTitle;
end;
procedure TForm1.btnViewClick(Sender: TObject);
begin
if ofd.Execute then
edFilePath.Text:=ofd.FileName;
end;
procedure TForm1.edStartAddressKeyPress(Sender: TObject; var Key: Char);
begin
if not (key in ['0'..'9',chr(VK_BACK),'a'..'f','A'..'F']) then
key:=#0;
end;
procedure TForm1.edEndAddressKeyPress(Sender: TObject; var Key: Char);
begin
if not (key in ['0'..'9',chr(VK_BACK),'a'..'f','A'..'F']) then
key:=#0;
end;
procedure TForm1.edKeyKeyPress(Sender: TObject; var Key: Char);
begin
if not (key in ['0'..'9',chr(VK_BACK)]) then
key:=#0;
end;
procedure TForm1.btnAttribClick(Sender: TObject);
begin
if SetSectionAttrib(edFilePath.Text) then
showmessage('代码段添加可写属性成功')
else
showmessage('代码段添加可写属性失败');
end;
procedure TForm1.btnExitClick(Sender: TObject);
begin
Close;
end;
end.
作者:壹只老虎
日期:2007-08-01
[培训]科锐逆向工程师培训第53期2025年7月8日开班!