看雪CTF2019 Q2第10题 开启时间之轮

第10题没有反调试,也没有壳,只有复杂的算法,用到了离散对数,素数,模幂等运算,看得头都大了。题目中用到了很多大整数,逆向的基础之一在于怎样确定每个函数的功能?献出我的一个笨方法,弄清楚函数的输入输出参数后,将大数换成数值小的,直接观察它们之间的关系,从而猜出它们间的关系。


譬如:分析sub_402650时,初始运行时第3、4个参数数值过大,不利于分析函数的功能。

00404889 |.  E8 C2DDFFFF   call    00402650

0014E99C  0018F0B4   //存放结果

0014E9A0  0014EB60   //64

0014E9A4  0014EBDC  //8个dword数

0014E9A8  0018F0A8   //7fff…ffed,8个dword

0014E9AC  0014EB0C


我们可以将第3个参数数值改为2,第4个参数数值改为0x111111,发现18F0B4处的结果为0x2710=64^2 mod 0x111111。从而确定sub_402650为幂指取模的运算。


此方法可以广泛应用到该程序的逆向过程中。


此外,为了快速发现数值间的关系,有必要表明大数的结构,在F5出伪代码时,将对应的数据类型改过来。

00000000 BN              struc ; (sizeof=0xC, mappedto_35) 00000000                                         ; XREF: add_401B00/r 00000000                                         ; sub_401B60/r ...

00000000 sign            dd ?                    ; XREF: add_401B00+3E/w 00000000                                         ; sub_401B60+3E/w ...

00000004 size_in_dword   dd ?                    ; XREF: add_401B00+31/w 00000004                                         ; sub_401B60+31/w ...

00000008 pdata           dd ?                    ; XREF: add_401B00+29/w 00000008                                         ; sub_401B60+29/w ...

0000000C BN              ends

sn前半部分、sn后半部分、name这3个关键数据被存储在一个结构中,最后传入到了校验函数final_check_404270中。

00000000 NNN             struc ; (sizeof=0x14, mappedto_34) 00000000                                         ; XREF: sub_403DB0/r

00000000 pdata           dd ?

00000004 data_len        dd ?                    ; XREF: sub_403DB0+1FD/o

00000008 str_or_numbase  dd ? 0000000C add_num         dd ?

00000010 maxcount        dd ? 00000014 NNN             ends

独立完成这道题时,在分析到0040468F   call   sub_403410时,卡壳了,往后拉还有那么多黑压压的代码行就胆怯。后来看了大佬们的wp,才明白了该题的思路,总结一下,做个笔记。


sn以XXXX分隔,前半部分即为a,后半部分记为b。

00403B8A     call    sub_404FB0


后半部分必须为数字,且第一个数字不能为0

00403C5B      call   _isdigit


.text:00403C3B                 cmp     byte ptr [eax], 30h

.text:00403C3E                 jz      loc_403D76


验证sn,返回结果必须为0

00404004    call    final_check_404270


final_check_404270为核心函数,里面有3个判断条件:


第1个条件:

4b

素数N=2^255-19=7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED


第2个条件:模方程

这里我们令a’=sn前半部分,最后一个字符+0xA,r=b-a’,循环6次的过程如下

sum0 = r^0/N                 3*1+0 =3

sum1 = r^1*0/N              +sum0/N = 3

sum2 = r^2*1/N              +sum1/N =(r^2+3)/N

sum3 = r^3*0/N              +sum2/N =(r^2+3)/N

sum4 = r^4*0x40/N +sum3/N = 0X40r^4/N + (r^2+3)/N

sum5 = r^5*0/N +sum4


最后得到的方程

(64r^4/N + (r^2 +3)/N)/n = a

0040468F  call    get_num_403410


这里我们令x=r^2,这里往回逆的时候要逆两次。化简后可得一个二次模方程。

64x^2 + x +3-a = 0(mod N)


从方程可知,求出a即可反推x,r最后求得b。那么我们继续分析,看如何求a值。


第3个条件:离散对数

1、将sn前半部分最后一位+0x0A,内容转换为0x19进制数,记作E;

2、米勒罗宾素性测试,确保E为素数;

3、 E与(N-1)最大公约数为1

4、检测计算

D = E^-1 mod (N-1)

X = A^D mod N

A = X^E mode N

N=0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED

这里我们已知A和X的四组数据

'100',0Ah           

9230197858975018299629857977411527954550899478307510809210520967346958600039

'101',0Ah         

50414221767352083765613498524674590844333823720255656432490557866777248860034

.102',0Ah

38377684164112914669201831650756813551072223314592288217929947158283532270268

'103',0Ah

13436195533519778671648120865743178010431697022400670384909515001970400645091

求D,求离散对数。利用作者dlp工具可以跑出D。

利用作者给出的:基于miracl运算库的 Pollard's kangaroos 方法求离散对数源代码以及编译好可运行的demo

LIMIT64= 95367431640625 , LEAPS= 9765626

solvediscrete logarithm problem - using Pollard's kangaroos

findd in:  y = g^d mod n, given(y, g , n),if: d < 64 bits

 

y=100

g=9230197858975018299629857977411527954550899478307510809210520967346958600039

n=57896044618658097711785492504343953926634992332820282019728792003956564819949

 

settingtrap ....

 

trapset! jumps = 9765626

Timecost 18 seconds 362ms

 

speed531 K/s

 

Gotcha!Time  cost 39 seconds 266 ms

 

jumps= 21326452, speed = 543 K/s

 

Discretelog: d =79821823136933


d= 79821823136933=0x4898F769D4A5,将其转换为25进制,最后一个字符-0xA,得出

sn前半部分a为:KCTFREADYK


wolframalpha解方程:

r^2 + 64r^4 + 3 =355419490699766887897429(mod 2**255-19)


解得:

r =1548396171915056368526513804948765619094392315806578106376668805448390390825


故第二部分为:

a’=sn前半部分,最后一个字符+0xA,r=b-a’

a’= 355419490699766887897429

b=1548396171915056368526513804948765619094392315806578106376668805448390390825

+355419490699766887897429

=1548396171915056368526513804948765619094392315806578461796159505215278288254


完整的key:

KCTFREADYKXXXX1548396171915056368526513804948765619094392315806578461796159505215278288254

推荐阅读更多精彩内容