首页
社区
课程
招聘
请教一个简单算法逆运算,高手勿笑,偶很菜
发表于: 2006-11-3 17:06 8294

请教一个简单算法逆运算,高手勿笑,偶很菜

2006-11-3 17:06
8294

最近跟了一个Crackme,算法基本搞懂了,在写注册机的时候,遇到一个问题,如下:

假设伪码为a,长度为j,crackme的算法为:
m:=0;
for i:=1 to j do
begin
  m:= m + m*4;
  m:= Ord(a[i])-$30 + m*2;
end;

得出的m如果等于$DDBEE106(假设是该值,其实是因机器不同而不同),则注册成功。现在的问题是,我现在已知$DDBEE106,如何逆运算得出伪码?

请高手指点,偶算法超菜。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (15)
雪    币: 110
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
大侠可以提供 Crackme 吗?
2006-11-3 17:15
0
雪    币: 102
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
最初由 springkang[DFCG 发布
最近跟了一个Crackme,算法基本搞懂了,在写注册机的时候,遇到一个问题,如下:

假设伪码为a,长度为j,crackme的算法为:
m:=0;
for i:=1 to j do
........

此代码的作用应该是将a[i]转化为16进制
DDBEE106他的十进制数字机为注册码3720274182
不知正确吗?
2006-11-3 17:26
0
雪    币: 260
活跃值: (81)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
估计是要穷举
2006-11-3 19:44
0
雪    币: 370
活跃值: (78)
能力值: ( LV9,RANK:970 )
在线值:
发帖
回帖
粉丝
5
最初由 mutouren 发布
此代码的作用应该是将a转化为16进制
DDBEE106他的十进制数字机为注册码3720274182
不知正确吗?


正解,就是16进制和10进制转换。
2006-11-3 20:16
0
雪    币: 2384
活跃值: (766)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
6
//这个算法的反算很简单。只需将机器码($DDBEE106)除2取余,得取余得到的数反转并转换成字符串就是注册码。如下是生成注册码的函数:
char* DeCrypt(unsigned long Code, char* lpOutSn)
{
        for (int i = 0; Code >= 9;i++)
        {
                char c = (char)(Code % 8);
                Code -= c;
                c += (char)(Code % 2);
                Code /= 2;
                lpOutSn[i] = c + (char)0x30;
        }
        lpOutSn[i] = (char)(Code + 0x30);
        for (int j = 0; j <= i; j++)
        {
                char tmp = lpOutSn[j];
                lpOutSn[j] = lpOutSn[i];
                lpOutSn[i] = tmp;
                i--;
        }
        return lpOutSn;
}

机器码:0xDDBEE106
注册码:440444044044444044400004000006
2006-11-3 20:22
0
雪    币: 2384
活跃值: (766)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
7
//Delphi代码
Function DeCrypt(Code:LongWord; lpOutSn:pChar):pChar;
var i,j:Integer;
    c,tmp:Char;
begin
        i := 0;
        while Code >= 9 do
        begin
                c := Char(Code mod 8);
                Code := Code - LongWord(c);
                c := Char(LongWord(c) + Code mod 2);
                Code := Code div 2;
                lpOutSn[i] := Char(Byte(c) + $30);
                i := i + 1;
        end;
        lpOutSn[i] := Char(Code+$30);
        j := 0;
        while j <= i do
        begin
                tmp := lpOutSn[j];
                lpOutSn[j] := lpOutSn[i];
                lpOutSn[i] := tmp;
                i := i - 1;
                j := j + 1;
        end;
        ResUlt := lpOutSn;
end;
2006-11-3 20:53
0
雪    币: 323
活跃值: (589)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
8
谢谢小虾,偶再看看.。

crackme上传。
上传的附件:
2006-11-3 21:19
0
雪    币: 323
活跃值: (589)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
9
最初由 mutouren 发布
此代码的作用应该是将a转化为16进制
DDBEE106他的十进制数字机为注册码3720274182
不知正确吗?


算法偶简化了,其实DDBEE106是根据GetVolumeInformationA再进行一些运算得出的,不是注册码。具体可以跟一下crackme。
2006-11-3 21:23
0
雪    币: 2384
活跃值: (766)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
10
我少看了一句m := m * 4的代码,
你所说的代码是将十六进制的值转成十进制的值的函数。
2006-11-3 21:41
0
雪    币: 323
活跃值: (589)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
11
最初由 小虾 发布
我少看了一句m := m * 4的代码,
你所说的代码是将十六进制的值转成十进制的值的函数。


1、第一句就是 m:=m*5
2、是的,如何将DDBEE106还原成十进制数。

只需将机器码($DDBEE106)除2取余,得取余得到的数反转并转换成字符串就是注册码

这是什么原理呢?
2006-11-3 22:17
0
雪    币: 2384
活跃值: (766)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
12
跟踪了一下CreaMe,算法很简单。注册码反算代码:
Function GetDeKey(Code:String):String;
var dwTmp,dwHigh:LongWord;
    dwLow:Array[0..1] of LongWord;
begin
  GetVolumeInformation(nil,pChar(@dwTmp),4,pDWORD(@dwHigh),dwTmp,dwTmp,pChar(@dwLow),8);
  dwHigh := dwHigh + dwLow[0];
  ResUlt := IntToStr(dwHigh);
end;
2006-11-3 22:59
0
雪    币: 2384
活跃值: (766)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
13
//这里有一处Anti-Debug代码,用插件可以很容易通过
004011A4   .  E8 BB020000   CALL <JMP.&kernel32.IsDebuggerPresent>   ; [IsDebuggerPresent
004011A9   .  0BC0          OR EAX,EAX
004011AB   .  74 05         JE SHORT CRACKME1.004011B2
004011AD   .  E9 41010000   JMP CRACKME1.004012F3
004011B2   >  E8 60010000   CALL CRACKME1.00401317 //取机器码函数

这个函数是取机器码函数,这个函数可以说就是注册机代码了,写注册机时可以照抄这里的代码
00401317  /$  55            PUSH EBP
00401318  |.  8BEC          MOV EBP,ESP
0040131A  |.  83C4 F4       ADD ESP,-0C
//调用GetVolumeInformationA函数获取机器码
0040131D  |.  68 FF000000   PUSH 0FF
00401322  |.  8D45 F4       LEA EAX,DWORD PTR SS:[EBP-C]
00401325  |.  50            PUSH EAX
00401326  |.  6A 00         PUSH 0
00401328  |>  6A 00         PUSH 0                                   ; |pMaxFilenameLength = NULL
0040132A  |.  8D45 FC       LEA EAX,DWORD PTR SS:[EBP-4]             ; |
0040132D  |.  50            PUSH EAX                                 ; |pVolumeSerialNumber
0040132E  |.  68 FF000000   PUSH 0FF                                 ; |MaxVolumeNameSize = FF (255.)
00401333  |.  8D45 F8       LEA EAX,DWORD PTR SS:[EBP-8]             ; |
00401336  |.  50            PUSH EAX                                 ; |VolumeNameBuffer
00401337  |.  6A 00         PUSH 0                                   ; |RootPathName = NULL
00401339  |.  E8 20010000   CALL <JMP.&kernel32.GetVolumeInformation>; \GetVolumeInformationA
0040133E  |.  8B45 FC       MOV EAX,DWORD PTR SS:[EBP-4]
00401341  |.  8B5D F4       MOV EBX,DWORD PTR SS:[EBP-C]
//取出ebp-4和ebp-c里的值进行相加后的和再转化成十进制的字符串就是注册码了
00401344  |.  03C3          ADD EAX,EBX
00401346  |.  E8 12000000   CALL CRACKME1.0040135D
0040134B  |.  2D 47434644   SUB EAX,44464347
00401350  |.  68 5C314000   PUSH CRACKME1.0040315C                   ;  ASCII "68B20274"
00401355  |.  50            PUSH EAX
00401356  |.  E8 69010000   CALL CRACKME1.004014C4
0040135B  |.  C9            LEAVE
0040135C  \.  C3            RETN

//这里开始获取用户输入的注册码开始进行验证
0040126E   .  6A 14         PUSH 14                                  ; /Count = 14 (20.)
00401270   .  8D45 F0       LEA EAX,DWORD PTR SS:[EBP-10]            ; |
00401273   .  50            PUSH EAX                                 ; |Buffer
00401274   .  FF35 35314000 PUSH DWORD PTR DS:[403135]               ; |hWnd = 000007DC
//获取用户输入的注册码
0040127A   .  E8 8B010000   CALL <JMP.&user32.GetWindowTextA>        ; \GetWindowTextA
0040127F   .  8D45 F0       LEA EAX,DWORD PTR SS:[EBP-10]
00401282   .  50            PUSH EAX
//注用户输入的注册码以十进制的字符转化成十进制的Int整数类型对应Delphi的StrToInt函数
00401283   .  E8 E8010000   CALL CRACKME1.00401470
对转化后注册码进行运算函数
00401288   .  E8 13010000   CALL CRACKME1.004013A0
验证注册码函数
0040128D   .  E8 2D010000   CALL CRACKME1.004013BF
00401292   .  84C0          TEST AL,AL
00401294   .  74 46         JE SHORT CRACKME1.004012DC
2006-11-3 23:14
0
雪    币: 323
活跃值: (589)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
14
最初由 小虾 发布
00401339 |. E8 20010000 CALL <JMP.&kernel32.GetVolumeInformation>; \GetVolumeInformationA
0040133E |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00401341 |. 8B5D F4 MOV EBX,DWORD PTR SS:[EBP-C]
//取出ebp-4和ebp-c里的值进行相加后的和再转化成十进制的字符串就是注册码了



分析得不错。
只是那个涵数的逆运算还是没搞懂。


00401394 |. C1C0 02 rol eax, 2
00401397 |. 0FC8 bswap eax
00401399 |. A3 68314000 mov [403168], eax //又跟了一下,昨天没仔细看到上面三句



多谢小虾费心了。

2006-11-4 10:38
0
雪    币: 2384
活跃值: (766)
能力值: (RANK:410 )
在线值:
发帖
回帖
粉丝
15
那个函数就是和Delphi的StrToInt函数一样的。Delphi的IntToStr就是这个函数的逆运算。
m:=0;
for i:=1 to j do
begin
  m:= m + m*4;
  m:= Ord(a[i])-$30 + m*2;
end;
2006-11-4 10:41
0
雪    币: 323
活跃值: (589)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
16
在delphi里跟踪了一下,果然如小虾所说,是strtoint,难怪觉得这个涵数眼熟,好像原来见过。

顺便说一下在delphi跟踪的方法:
var
   s:string;
   i:integer;
begin
  s:='123456';
  i:= strtoint(s);  //这里下断,断下后点view->debug->CPU
end;

00407CBE E851AEFFFF       call @ValLong //跟进去

复制下来的汇编代码:
00402B64 742D             jz +$2d
00402B66 80EB30           sub bl,$30  // ord(a[i])-$30
00402B69 80FB09           cmp bl,$09
00402B6C 7725             jnbe +$25
00402B6E 39F8             cmp eax,edi
00402B70 7721             jnbe +$21
00402B72 8D0480           lea eax,[eax+eax*4]  // m:= m+m*4
00402B75 01C0             add eax,eax  // m*2
00402B77 01D8             add eax,ebx  //m:= ord(a[i])-$30 + m
00402B79 8A1E             mov bl,[esi]
00402B7B 46               inc esi
00402B7C 84DB             test bl,bl
00402B7E 75E6             jnz -$1a
2006-11-4 11:09
0
游客
登录 | 注册 方可回帖
返回
//