180522 安卓-DDCTF2018(RSA)

RSA

JAVA层没什么东西,直接将输入送入了Native层的stringFromJNI函数
这个函数垃圾代码极其的多
建议动态调试,跟随输入值来观察计算过程


在主函数中首先用gpower生成了32个字节的i²Table,又GetTicks取了两次时间,然而都没有用上

sub_3133C调用了input,从其中用到的字符串

“basic_string::_S_construct null not valid”

来看,应该是静态编译的basic_string类的构造函数

结构体中存放了字符串的长度和其他信息,将指针送给了第一个参数

sub_309E0中没有改变字符串,只是把string的指针送给了返回值,因此就不多纠结了
跟入那个长的很像库函数名字很奇葩但其实就是核心函数的prj函数

上来第一句
if ( *(_DWORD *)(v2 - 12) == 31 )
虽然一般都能猜出来这个31大概就是input的长度,但较真的话往前翻也能在sub_309E0中找到根据,或者动调可以更直观地看到这个数据


继续往下,逐字节异或了byte_4DECB数组,很常规的操作

这里的操作看起来比较复杂,但理清了其实很简单
关键的check其实只有中间那句v10[10]!=*v10
问题在于判断条件何时满足

分析一下,要j>=1,则v11>=10,即ii和v10都已+10
而v10的初值是&d[-10],也就是说异或后的字符串需要从0-30皆满足a[i]==a[i+10]的关系
也就是一个长为10字节的字符串循环3.1遍

接着将d[10]赋0,也就是仅保留一遍该字符串

用d构造了一个basic_string,将其通过atoll转成整数保存下来

下面的操作比较有意思,将两个字符串构造成string
那个名字超长的函数点进去可以发现是return j_std::map,std::allocator>>::operator[](a1, a2);
就是STL的map对象,pair对是

for i in range(len(a)):
    dic[a[i]] = i//2


第二个循环则遍历字符串b,将每个值的value取出连接在nptr中,最后atoll转成一个大整数

当然,比赛的时候没工夫慢慢逆23333直接动调看atoll的结果就是了


最后将两个整数相除,IDA反编译的结果比较乱,需要自己找准变量看

目标是return 1,即要r=1
那么v24必须为0,虽然没有给出v24的来源,不过在栈中可以看到

__int64 v24; // r2@24

v24指的是r2,x86和ARM中的除法函数都是会同时计算出商和余数的,并且余数通常会被放在备选寄存器中,商视操作数长度有时存在返回值寄存器中,有时被拆分成高低两段存在两个寄存器中
而IDA反编译时通常仅关注调用约定中的返回值寄存器,导致这里的v24不知来由

说了这么多,还是动调最方便啦~
因此这里要求big_n整除input_n

继续往下走
v27=1 => v25=0/HIDWORD(input_n)

你可能感兴趣的:(CrackMe,Android)