三年三班三井寿 发表于 2019-4-29 21:36

160个CrackMe之111,一个关于浮点数操作的简单小程序

最近在学安卓,没咋上论坛,主要也没啥时间。今晚还是腾出了一点时间去搞之前的crackme。
这次程序比之前发的053,081都要简单不少,但同样在论坛上没有找到破解的序列号,
https://www.52pojie.cn/thread-921654-1-1.html
https://www.52pojie.cn/thread-926825-1-1.html

程序主界面看上去很普通,一个Name/Serial的CM,不过分析后会发现还是比一般Name/Serial要简单的


程序很小,基本上不存在关键点定位的问题,貌似其他五星难度的也都很容易定位,基本就是纯算法逆向。
当然了,这个程序肯定不会有五星,如果不是操作浮点数的话,我觉得就是一个一星题。

很明显,上面两个获取name,Serial文本内容,下面两个弹窗判断,而验证函数就是中间夹着的sub_0040134A 了。返回1正确,0错误
跟进去之后,整个代码也没多长,不过都是一些浮点数的计算。半个多月不接触X86很多都记不得了(其实本来也没记得这些不怎么常用的指令)
这时候我们,上IDA F5X
当然是去学习这些指令啊√


进入到函数内部,它直截了当地就把name和Serial转变成了浮点数(atof),并向下取整(floor)
0040134A/$55            PUSH EBP
0040134B|.89E5          MOV EBP,ESP
0040134D|.83EC 68       SUB ESP,0x68
00401350|.FF75 08       PUSH                            ; /s = "245850922"
00401353|.E8 78010000   CALL <JMP.&CRTDLL.atof>                  ; \atof
00401358|.DD55 E8       FST QWORD PTR SS:
0040135B|.83EC 08       SUB ESP,0x8
0040135E|.DD1C24      FSTP QWORD PTR SS:
00401361|.E8 82010000   CALL <JMP.&CRTDLL.floor>
00401366|.DD5D F8       FSTP QWORD PTR SS:
00401369|.FF75 0C       PUSH                            ; /s = "411557987"
0040136C|.E8 5F010000   CALL <JMP.&CRTDLL.atof>                  ; \atof
00401371|.DD55 D8       FST QWORD PTR SS:
00401374|.83EC 08       SUB ESP,0x8
00401377|.DD1C24      FSTP QWORD PTR SS:
0040137A|.E8 69010000   CALL <JMP.&CRTDLL.floor>
0040137F|.83C4 18       ADD ESP,0x18
00401382|.DD55 F0       FST QWORD PTR SS:





紧接着进行了一系列地判断,当然很多都是多余地判断
并且每个判断形式都差不多,搞懂一个其他的也就一个样。(实际上只有前两个判断起作用)

第一步,先将上面得到的两个整数相乘,并且和0比较,若为0则直接return 0;
第二个判断是比较name和Serial,它们不能相等.
第三个第四个是为了name和Serial不为0(1成立的条件下这是必然的)
下两个是为了使name和Serial小于10000000000(也是多余的,因为在之前GetDlgItemText的时候指定了最大读取10位)
00401377|.DD1C24      FSTP QWORD PTR SS:
0040137A|.E8 69010000   CALL <JMP.&CRTDLL.floor>
0040137F|.83C4 18       ADD ESP,0x18
00401382|.DD55 F0       FST QWORD PTR SS:            ;name压入st0
00401385|.DC4D F8       FMUL QWORD PTR SS:            ;name*psd
00401388|.D9EE          FLDZ                                     ;压入0
0040138A|.DED9          FCOMPP                                 ;比较st0,st1;name*psd与0比较
0040138C|.DFE0          FSTSW AX                                 ;设置AX为FST
0040138E|.9E            SAHF                                     ;AH赋值给段寄存器低8位
0040138F|.75 07         JNZ SHORT 111.00401398                   ;name*psd不能等于0
00401391|.31C0          XOR EAX,EAX
00401393|.E9 96000000   JMP <111.return eax>
00401398|>DD45 F8       FLD QWORD PTR SS:               ;name
0040139B|.DC5D F0       FCOMP QWORD PTR SS:
0040139E|.DFE0          FSTSW AX                                 ;name不能等于psd
004013A0|.9E            SAHF
004013A1|.75 07         JNZ SHORT 111.004013AA
004013A3|.31C0          XOR EAX,EAX
004013A5|.E9 84000000   JMP <111.return eax>
004013AA|>DD45 F8       FLD QWORD PTR SS:
004013AD|.DD5D C8       FSTP QWORD PTR SS:             ;name
004013B0|.D9E8          FLD1
004013B2|.DD55 C0       FST QWORD PTR SS:            ;40:1.0
004013B5|.DC5D C8       FCOMP QWORD PTR SS:            ;name不能为0(貌似这步判断没什么用)
004013B8|.DFE0          FSTSW AX
004013BA|.9E            SAHF
004013BB|.77 2D         JA SHORT <111.return 0>
004013BD|.DF2D 38304000 FILD QWORD PTR DS:             ;10000000000.00000000
004013C3|.DD55 B8       FST QWORD PTR SS:
004013C6|.DC5D C8       FCOMP QWORD PTR SS:
004013C9|.DFE0          FSTSW AX
004013CB|.9E            SAHF
004013CC|.72 1C         JB SHORT <111.return 0>                  ;name需小于10000000000.00000000
004013CE|.DD45 F0       FLD QWORD PTR SS:
004013D1|.DD5D B0       FSTP QWORD PTR SS:             ;50:psd
004013D4|.DD45 C0       FLD QWORD PTR SS:            ;40:1.0
004013D7|.DC5D B0       FCOMP QWORD PTR SS:            ;psd不能为0
004013DA|.DFE0          FSTSW AX
004013DC|.9E            SAHF
004013DD|.77 0B         JA SHORT <111.return 0>
004013DF|.DD45 B8       FLD QWORD PTR SS:
004013E2|.DC5D B0       FCOMP QWORD PTR SS:
004013E5|.DFE0          FSTSW AX
004013E7|.9E            SAHF                                     ;psd需小于10000000000.00000000
004013E8|.73 04         JNB SHORT 111.004013EE
004013EA >|>31C0          XOR EAX,EAX
004013EC|.EB 40         JMP SHORT <111.return eax>




判断完就是一系列的计算,将name和Serial求正线值再乘10的16次方,最终将结果向下取整,若结果为0,则返回1
004013EC|. /EB 40         JMP SHORT <111.return eax>
004013EE|> |DD45 F8       FLD QWORD PTR SS:
004013F1|. |D9FE          FSIN
004013F3|. |DD5D A8       FSTP QWORD PTR SS:             ;0x58:sin(name)
004013F6|. |DD45 F0       FLD QWORD PTR SS:
004013F9|. |D9FE          FSIN
004013FB|. |DD5D A0       FSTP QWORD PTR SS:             ;0x60:sin(psd)
004013FE|. |DD45 A8       FLD QWORD PTR SS:
00401401|. |DC4D A0       FMUL QWORD PTR SS:             ;sin(name)*sin(psd)
00401404|. |DF2D 30304000 FILD QWORD PTR DS:             ;10^16
0040140A|. |DEC9          FMULP ST(1),ST                           ;sin(name)*sin(psd)*10^16
0040140C|. |83EC 08       SUB ESP,0x8
0040140F|. |DD1C24      FSTP QWORD PTR SS:
00401412|. |E8 D1000000   CALL <JMP.&CRTDLL.floor>
00401417|. |83C4 08       ADD ESP,0x8
0040141A|. |DD5D 98       FSTP QWORD PTR SS:
0040141D|. |D9EE          FLDZ
0040141F|. |DC5D 98       FCOMP QWORD PTR SS:
00401422|. |DFE0          FSTSW AX
00401424|. |9E            SAHF
00401425|. |75 05         JNZ SHORT <111.return 0>               ;sin(name)*sin(psd)*10^16需要小于1
00401427|. |31C0          XOR EAX,EAX
00401429|. |40            INC EAX
0040142A|. |EB 02         JMP SHORT <111.return eax>
0040142C >|> |31C0          XOR EAX,EAX
0040142E >|> \C9            LEAVE
0040142F\.C3            RETN



整个流程这么多,因该还是比较容易的,就是浮点计算的汇编看的有点陌生,下面就是写注册机。
两个不相同的整数取正弦值相乘,再乘10^16,最终结果要小于1大于0(向下取整为0)
而这两个整数的范围是一开始获取文本内容时候就确定的,最高10位字符串(包含0),而并非后面的10000000000
所以我们只要保证每个正弦的值小于10的-8次方就行了(也就是最高10的-9)
然后就可以很容易写出注册机了,当然需要注意一下两个sin的符号需要同号
#include <vector>
vector<DWORD64> res;
int main()
{
        printf("第一组\n");
        for (DWORD64 i = 1; i < 1000000000; i++)
        {
                if (sin(i) < 1e-8&&sin(i) > -(1e-8))
                {
                        if (sin(i) > 0)
                                printf("%lld\n", i);
                        else
                                res.push_back(i);
                }       
        }
        printf("第二组\n");
        for (DWORD i = 0; i < res.size(); i++)
                printf("%lld\n", res);
        return 0;
}


当然,也可以不穷举,通过sin(n*pi)=0去写注册机,不过试了下只用double去存pi的话貌似还不够精准。
如果有大佬有什么好方法的话也欢迎来讨论{:17_1082:}

92013 发表于 2019-5-10 22:49

支持一下。

92013 发表于 2019-5-11 23:18

不错 支持下

想补天 发表于 2020-3-24 06:39

能不能带做项目
页: [1]
查看完整版本: 160个CrackMe之111,一个关于浮点数操作的简单小程序