aLoNg3x.2分析

重新看了下aLoNg3x.2,有好多不懂的。跟了很久后,大概看了下别人的流程,才知道怎么算序列号···但写代码捉急。

拿到程序,大体看还是输名字和序列号。查壳,没有加壳,因为是Delphi写的,所以按钮事件还是通过DE来找。

主要的按钮就是RegsisterClick注册按钮,和AgainClick检测按钮。整个程序的流程:

1.先输入name,长度需要大于4位

2.输入含有字符的字符串,长度大于5位

3.输入正确的注册码,然后注册键按钮会消失

4.输入含有字符的字符串,长度大于5位

5.输入正确的注册码。输错的话,注册键按钮会恢复

最后again按钮消失,注册成功。

流程借鉴别人看起来很简单,自己跟就不是那么一回事了。然后分析下两个主要按钮的代码。

首先根据DE中的地址,给注册键和again键下断。F9运行。程序跑起来。然后点击注册按钮,断到了注册函数中。

00442F28  /.  55             push ebp                             ;  Register
00442F29  |.  8BEC           mov ebp,esp
00442F2B  |.  83C4 F8        add esp,-0x8                         ;  开辟局部变量
00442F2E  |.  53             push ebx
00442F2F  |.  56             push esi
00442F30  |.  33C9           xor ecx,ecx                          ;  aLoNg3x_.0041E570
00442F32  |.  894D F8        mov [local.2],ecx                    ;  aLoNg3x_.0041E570
00442F35  |.  8BD8           mov ebx,eax
00442F37  |.  33C0           xor eax,eax
00442F39  |.  55             push ebp
00442F3A  |.  68 22304400    push aLoNg3x_.00443022               ;  异常处理程序
00442F3F  |.  64:FF30        push dword ptr fs:[eax]
00442F42  |.  64:8920        mov dword ptr fs:[eax],esp
00442F45  |.  8D55 F8        lea edx,[local.2]                    ;  传参
00442F48  |.  8B83 DC020000  mov eax,dword ptr ds:[ebx+0x2DC]     ;  函数地址
00442F4E  |.  E8 ED02FEFF    call <aLoNg3x_.GetText>
00442F53  |.  8B45 F8        mov eax,[local.2]                    ;  获取CODE的值
00442F56  |.  8D55 FC        lea edx,[local.1]
00442F59  |.  E8 FAF9FBFF    call <aLoNg3x_.calc>                 ;  输入的字符串转换成一组数转化成16进制
00442F5E  |.  8BF0           mov esi,eax
00442F60  |.  837D FC 00     cmp [local.1],0x0                    ;  如果CODE输入是空的或者是非数字,local1=1
00442F64  |.  74 37          je short aLoNg3x_.00442F9D           ;  如果输入格式正确,不会去设置[0x445830]
00442F66  |.  B8 38304400    mov eax,aLoNg3x_.00443038            ;  ASCII 59,"ou MUST insert a valid Long Integer Value in the Code Editor... Thank you :)"
00442F6B  |.  E8 00F6FFFF    call aLoNg3x_.00442570
00442F70  |.  8D55 F8        lea edx,[local.2]
00442F73  |.  8B83 DC020000  mov eax,dword ptr ds:[ebx+0x2DC]
00442F79  |.  E8 C202FEFF    call <aLoNg3x_.GetText>              ;  获取编辑框的值
00442F7E  |.  8B45 F8        mov eax,[local.2]
00442F81  |.  E8 06FBFFFF    call <aLoNg3x_.Set445830>            ;  这个函数设置[0x445830]位置的值
00442F86  |.  A3 30584400    mov dword ptr ds:[0x445830],eax      ;  这里关键,这里如果设置为0,
00442F8B  |.  BA 90304400    mov edx,aLoNg3x_.00443090            ;  UNICODE "0"
00442F90  |.  8B83 DC020000  mov eax,dword ptr ds:[ebx+0x2DC]
00442F96  |.  E8 D502FEFF    call aLoNg3x_.00423270
00442F9B  |.  EB 6F          jmp short aLoNg3x_.0044300C
00442F9D  |>  85F6           test esi,esi                         ;  esi存储的是CODE字符串转换后的值
00442F9F  |.  7E 5A          jle short aLoNg3x_.00442FFB
00442FA1  |.  8D55 F8        lea edx,[local.2]
00442FA4  |.  8B83 D8020000  mov eax,dword ptr ds:[ebx+0x2D8]
00442FAA  |.  E8 9102FEFF    call <aLoNg3x_.GetText>              ;  获取name,长度在eax
00442FAF  |.  8B4D F8        mov ecx,[local.2]                    ;  name的值
00442FB2  |.  8BD6           mov edx,esi                          ;  CODE转换后的值
00442FB4  |.  A1 30584400    mov eax,dword ptr ds:[0x445830]
00442FB9  |.  E8 EAF9FFFF    call <aLoNg3x_.test>                 ;  检测输入的CODE
00442FBE  |.  84C0           test al,al                           ;  输入正确后,al为非0,注册按钮消失,again按钮出现。
00442FC0  |.  74 30          je short aLoNg3x_.00442FF2
00442FC2  |.  33D2           xor edx,edx
00442FC4  |.  8B83 CC020000  mov eax,dword ptr ds:[ebx+0x2CC]
00442FCA  |.  E8 6101FEFF    call aLoNg3x_.00423130
00442FCF  |.  B2 01          mov dl,0x1
00442FD1  |.  8B83 E8020000  mov eax,dword ptr ds:[ebx+0x2E8]
00442FD7  |.  E8 5401FEFF    call aLoNg3x_.00423130
00442FDC  |.  33D2           xor edx,edx
00442FDE  |.  8B83 D8020000  mov eax,dword ptr ds:[ebx+0x2D8]
00442FE4  |.  8B08           mov ecx,dword ptr ds:[eax]           ;  aLoNg3x_.004427AC
00442FE6  |.  FF51 60        call dword ptr ds:[ecx+0x60]
00442FE9  |.  33C0           xor eax,eax
00442FEB  |.  A3 30584400    mov dword ptr ds:[0x445830],eax
00442FF0  |.  EB 1A          jmp short aLoNg3x_.0044300C
00442FF2  |>  33C0           xor eax,eax
00442FF4  |.  A3 30584400    mov dword ptr ds:[0x445830],eax
00442FF9  |.  EB 11          jmp short aLoNg3x_.0044300C
00442FFB  |>  B8 9C304400    mov eax,aLoNg3x_.0044309C
00443000  |.  E8 6BF5FFFF    call aLoNg3x_.00442570
00443005  |.  33C0           xor eax,eax
00443007  |.  A3 30584400    mov dword ptr ds:[0x445830],eax
0044300C  |>  33C0           xor eax,eax
0044300E  |.  5A             pop edx                              ;  aLoNg3x_.004245C0
0044300F  |.  59             pop ecx                              ;  aLoNg3x_.004245C0
00443010  |.  59             pop ecx                              ;  aLoNg3x_.004245C0
00443011  |.  64:8910        mov dword ptr fs:[eax],edx
00443014  |.  68 29304400    push aLoNg3x_.00443029
00443019  |>  8D45 F8        lea eax,[local.2]
0044301C  |.  E8 9707FCFF    call <aLoNg3x_.引用计数减1>
00443021  \.  C3             retn

这块的代码,主要做的事:获取输入的CODE字符串,将其转换成十六进制,这是针对输入纯数字,比如输入10,然后会转换成0xA保存起来,然后转换函数中,会设置局部变量local1的值,如果CODE输入的是空或者带字母的字符串,就会去设置0x445830这个地址的值具体如何设置在下面的函数中有分析。设置完这个内存地址的值后,就通过使用这个值,去计算Name字符串生成的注册码。然后检测是否正确,如果输入正确,那么注册键就消失,出现一个再次尝试的按钮。

00442F81  |.  E8 06FBFFFF    call <aLoNg3x_.Set445830> 函数内部

00442A8C >/$  55             push ebp                            ;设置内存地址0x445830值的函数
00442A8D  |.  8BEC           mov ebp,esp
00442A8F  |.  51             push ecx
00442A90  |.  53             push ebx
00442A91  |.  56             push esi
00442A92  |.  57             push edi
00442A93  |.  8945 FC        mov [local.1],eax                    ;  aLoNg3x_.0044309C
00442A96  |.  8B45 FC        mov eax,[local.1]
00442A99  |.  E8 4A11FCFF    call <aLoNg3x_.useCount>             ;引用计数
00442A9E  |.  33C0           xor eax,eax                          ;  aLoNg3x_.0044309C
00442AA0  |.  55             push ebp
00442AA1  |.  68 212B4400    push aLoNg3x_.00442B21
00442AA6  |.  64:FF30        push dword ptr fs:[eax]
00442AA9  |.  64:8920        mov dword ptr fs:[eax],esp           ;seh异常处理函数
00442AAC  |.  8B45 FC        mov eax,[local.1]
00442AAF  |.  E8 800FFCFF    call <aLoNg3x_.字符串长度>
00442AB4  |.  83F8 05        cmp eax,0x5                          ;  长度必须大于5
00442AB7  |.  7E 3D          jle short aLoNg3x_.00442AF6
00442AB9  |.  BE 7B030000    mov esi,0x37B                        ;  第一个数0x37B
00442ABE  |.  8B45 FC        mov eax,[local.1]
00442AC1  |.  E8 6E0FFCFF    call <aLoNg3x_.字符串长度>
00442AC6  |.  8BD8           mov ebx,eax                          ;  aLoNg3x_.0044309C
00442AC8  |.  4B             dec ebx
00442AC9  |.  85DB           test ebx,ebx                         ;字符串长度
00442ACB  |.  7E 2B          jle short aLoNg3x_.00442AF8
00442ACD  |.  B9 01000000    mov ecx,0x1
00442AD2  |>  8B45 FC        /mov eax,[local.1]                   ;  检测字符串序列号的算法
00442AD5  |.  0FB60408       |movzx eax,byte ptr ds:[eax+ecx]     ;  取第ecx个字符,转换成assic
00442AD9  |.  BF 11000000    |mov edi,0x11
00442ADE  |.  33D2           |xor edx,edx
00442AE0  |.  F7F7           |div edi                             ;  第一个字符的assic/0x11
00442AE2  |.  42             |inc edx                             ;  余数+1
00442AE3  |.  8B45 FC        |mov eax,[local.1]
00442AE6  |.  0FB64408 FF    |movzx eax,byte ptr ds:[eax+ecx-0x1] ;  取第ecx-1个字符的assic
00442AEB  |.  0FAFD0         |imul edx,eax                        ;  edx==(余数计算结果edx)*第ecx-1个assic的值
00442AEE  |.  03F2           |add esi,edx                         ;  0x37B+计算结果,累加
00442AF0  |.  41             |inc ecx                             ;  下标++
00442AF1  |.  4B             |dec ebx                             ;  长度--
00442AF2  |.^ 75 DE          \jnz short aLoNg3x_.00442AD2
00442AF4  |.  EB 02          jmp short aLoNg3x_.00442AF8
00442AF6  |>  33F6           xor esi,esi
00442AF8  |>  8BC6           mov eax,esi                          ;  计算出esi
00442AFA  |.  B9 48710000    mov ecx,0x7148                       ;  ecx=0x7148
00442AFF  |.  99             cdq
00442B00  |.  F7F9           idiv ecx                             ;  esi/0x7148
00442B02  |.  8BC2           mov eax,edx                          ;  eax==余数
00442B04  |.  99             cdq
00442B05  |.  33C2           xor eax,edx
00442B07  |.  2BC2           sub eax,edx
00442B09  |.  8BD8           mov ebx,eax                          ;  ebx=计算结果
00442B0B  |.  33C0           xor eax,eax                          ;  aLoNg3x_.0044309C
00442B0D  |.  5A             pop edx                              ;  0019F620
00442B0E  |.  59             pop ecx                              ;  0019F620
00442B0F  |.  59             pop ecx                              ;  0019F620
00442B10  |.  64:8910        mov dword ptr fs:[eax],edx
00442B13  |.  68 282B4400    push aLoNg3x_.00442B28
00442B18  |>  8D45 FC        lea eax,[local.1]                    ;  eax==name字符串
00442B1B  |.  E8 980CFCFF    call <aLoNg3x_.引用计数减1>
00442B20  \.  C3             retn
00442B21   .^ E9 5207FCFF    jmp aLoNg3x_.00403278
00442B26   .^ EB F0          jmp short aLoNg3x_.00442B18
00442B28   .  8BC3           mov eax,ebx                          ;  计算结果
00442B2A   .  5F             pop edi                              ;  0019F620
00442B2B   .  5E             pop esi                              ;  0019F620
00442B2C   .  5B             pop ebx                              ;  0019F620
00442B2D   .  59             pop ecx                              ;  0019F620
00442B2E   .  5D             pop ebp                              ;  0019F620
00442B2F   .  C3             retn

要进入这个函数,首先必须输入带有字母的字符串,进入函数后,首先检测字符串的长度是否大于5,小于等于5退出。满足条件后,进行计算。逐一获取CODE字符串的值,比如我输入"abcdef",先取出b,然后b的assic/0x11得到一个余数tmp,tmp+1,然后再取a,用tmp*=a的assic,然后计算结果+最开始的数字0x37b,计算出一个数字NUM,接着再取c  和  b继续计算,累加NUM,把字符串都计算完后,最后得到一个数字ret。

用这个ret/0x7148,计算出一个余数,那么这个余数就是设置那个455830地址的值。接下来,因为CODE输入的如果是非数字,会弹一次警告框,此时如果输入的是带字母的字符串,长度大于5,那么455830就会被设置成一个非0值。程序继续往下走,就会去将再次输入的CODE(必须是纯数字)进行检测,看是否正确。而此时输入的CODE,其实是对输入的name进行计算的出来的。

00442FB9  |.  E8 EAF9FFFF    call <aLoNg3x_.test>                 ;  检测输入的CODE

004429A8 >/$  55             push ebp
004429A9  |.  8BEC           mov ebp,esp
004429AB  |.  83C4 F4        add esp,-0xC
004429AE  |.  53             push ebx
004429AF  |.  56             push esi
004429B0  |.  57             push edi
004429B1  |.  894D F8        mov [local.2],ecx                    ;  name
004429B4  |.  8955 FC        mov [local.1],edx                    ;  CODE转换
004429B7  |.  8BF8           mov edi,eax                          ;  eax为0
004429B9  |.  8B45 F8        mov eax,[local.2]
004429BC  |.  E8 2712FCFF    call <aLoNg3x_.useCount>             ;  引用计数
004429C1  |.  33C0           xor eax,eax                          ;  aLoNg3x_.0044309C
004429C3  |.  55             push ebp
004429C4  |.  68 7A2A4400    push aLoNg3x_.00442A7A
004429C9  |.  64:FF30        push dword ptr fs:[eax]
004429CC  |.  64:8920        mov dword ptr fs:[eax],esp           ;  异常处理函数的安装
004429CF  |.  8B45 F8        mov eax,[local.2]
004429D2  |.  E8 5D10FCFF    call <aLoNg3x_.字符串长度>                ;  获取的是长度?
004429D7  |.  83F8 04        cmp eax,0x4
004429DA  |.  0F8E 82000000  jle aLoNg3x_.00442A62                ;  name的长度要大于4,否则就退出了
004429E0  |.  33DB           xor ebx,ebx                          ;  ebx=0
004429E2  |.  8B45 F8        mov eax,[local.2]
004429E5  |.  E8 4A10FCFF    call <aLoNg3x_.字符串长度>
004429EA  |.  85C0           test eax,eax                         ;  aLoNg3x_.0044309C
004429EC  |.  7E 38          jle short aLoNg3x_.00442A26
004429EE  |.  8945 F4        mov [local.3],eax                    ;  aLoNg3x_.0044309C
004429F1  |.  BE 01000000    mov esi,0x1
004429F6  |>  8B45 F8        /mov eax,[local.2]
004429F9  |.  E8 3610FCFF    |call <aLoNg3x_.字符串长度>
004429FE  |.  83F8 01        |cmp eax,0x1
00442A01  |.  7C 1D          |jl short aLoNg3x_.00442A20
00442A03  |>  8B55 F8        |/mov edx,[local.2]
00442A06  |.  0FB65432 FF    ||movzx edx,byte ptr ds:[edx+esi-0x1>;  取每一个字符到edx
00442A0B  |.  8B4D F8        ||mov ecx,[local.2]
00442A0E  |.  0FB64C01 FF    ||movzx ecx,byte ptr ds:[ecx+eax-0x1>;  倒序取第n个字符给ecx
00442A13  |.  0FAFD1         ||imul edx,ecx
00442A16  |.  0FAFD7         ||imul edx,edi                       ;  edi=0,任何数乘都为0
00442A19  |.  03DA           ||add ebx,edx                        ;  ebx+edi始终为0
00442A1B  |.  48             ||dec eax                            ;  aLoNg3x_.0044309C
00442A1C  |.  85C0           ||test eax,eax                       ;  aLoNg3x_.0044309C
00442A1E  |.^ 75 E3          |\jnz short aLoNg3x_.00442A03
00442A20  |>  46             |inc esi
00442A21  |.  FF4D F4        |dec [local.3]
00442A24  |.^ 75 D0          \jnz short aLoNg3x_.004429F6
00442A26  |>  8BC3           mov eax,ebx                          ;  输入的name计算出一组数
00442A28  |.  99             cdq
00442A29  |.  33C2           xor eax,edx
00442A2B  |.  2BC2           sub eax,edx
00442A2D  |.  B9 2A2C0A00    mov ecx,0xA2C2A                      ;  计算出来的数字/0xA2C2A
00442A32  |.  99             cdq
00442A33  |.  F7F9           idiv ecx
00442A35  |.  8BDA           mov ebx,edx                          ;  ebx==余数
00442A37  |.  8B45 FC        mov eax,[local.1]                    ;  取CODE转换后的值
00442A3A  |.  B9 59000000    mov ecx,0x59
00442A3F  |.  99             cdq
00442A40  |.  F7F9           idiv ecx                             ;  name转换后的数/0x59
00442A42  |.  8BC8           mov ecx,eax                          ;  ecx=商
00442A44  |.  8B45 FC        mov eax,[local.1]
00442A47  |.  BE 50000000    mov esi,0x50
00442A4C  |.  99             cdq
00442A4D  |.  F7FE           idiv esi                             ;  name转换后的数/0x50
00442A4F  |.  03CA           add ecx,edx                          ;  第一个结果的 商+第二个结果的 余数
00442A51  |.  41             inc ecx                              ;  结果+1
00442A52  |.  894D FC        mov [local.1],ecx                    ;  结果
00442A55  |.  3B5D FC        cmp ebx,[local.1]                    ;  结果和计算出来的数相同
00442A58  |.  75 04          jnz short aLoNg3x_.00442A5E
00442A5A  |.  B3 01          mov bl,0x1                           ;  相同,bl=1
00442A5C  |.  EB 06          jmp short aLoNg3x_.00442A64
00442A5E  |>  33DB           xor ebx,ebx
00442A60  |.  EB 02          jmp short aLoNg3x_.00442A64
00442A62  |>  33DB           xor ebx,ebx
00442A64  |>  33C0           xor eax,eax                          ;  eax清空=0
00442A66  |.  5A             pop edx                              ;  0019F620
00442A67  |.  59             pop ecx                              ;  0019F620
00442A68  |.  59             pop ecx                              ;  0019F620
00442A69  |.  64:8910        mov dword ptr fs:[eax],edx
00442A6C  |.  68 812A4400    push aLoNg3x_.00442A81
00442A71  |>  8D45 F8        lea eax,[local.2]
00442A74  |.  E8 3F0DFCFF    call <aLoNg3x_.引用计数减1>
00442A79  \.  C3             retn
00442A7A   .^ E9 F907FCFF    jmp aLoNg3x_.00403278
00442A7F   .^ EB F0          jmp short aLoNg3x_.00442A71
00442A81   .  8BC3           mov eax,ebx                          ;  也就是输入正确,eax==1
00442A83   .  5F             pop edi                              ;  0019F620
00442A84   .  5E             pop esi                              ;  0019F620
00442A85   .  5B             pop ebx                              ;  0019F620
00442A86   .  8BE5           mov esp,ebp
00442A88   .  5D             pop ebp                              ;  0019F620
00442A89   .  C3             retn

这个函数是检测CODE输入是否正确的函数。

在调用这个函数开始的位置,有这么一句:

这个就是上面计算出来的那个余数sss。

进入函数后,可以看到edi=eax,然后就取输入的name,来计算生成的序列号,比如输入"123456",

首先取‘1’,然后取‘6’,注意都是用assic计算 。‘1’*‘6’,计算出结果num1,num2=num1*sss,然后累加,这里用TMP表示累加数,TMP+=num2,然后取‘1’*‘5’,当一轮取完,开始‘2’*‘6’进行下一轮,直到‘6’*‘6’这一轮走完,TMP就累加结束。

然后用TMP/0xA2C2A计算出一个余数,存到ebx中。

接着用输入的name,也就是转化成十六进制的数nameNum

name转换后的数nameNum/0x59的商  n1
name转换后的数nameNum/0x50的余数  n2

result=n1+n2+1

ebx的值和result的值如果相等,那么序列号就正确。

用式子表示就是  x/0x59+x%0x50+1=上面说过的那个余数sss。

那个余数可以是随便输入一串字母,就算出来了,但是这里如何求x(x就是正确的序列号)转成代码,算法太渣,想不出来。

这是爆破的,序列号等会算了再写写,然后again中调用的函数和注册的一样,都是先输入一串带字母的数,计算出一个余数,再输入正确的序列号,检测通过后,消失。

 

爆破就算了说吧。

猜你喜欢

转载自blog.csdn.net/weixin_42489582/article/details/85398669