首页
社区
课程
招聘
[原创](r0_0t) 叹息之墙 writeup
2018-10-1 13:14 3013

[原创](r0_0t) 叹息之墙 writeup

2018-10-1 13:14
3013

拿到程序之后跑一下,基本没有什么信息。
用OD打开,搜索字符串,找到了运行程序时的输出以及输入正确、错误对应的输出。
OD字符串
用IDA打开。。。
叹气之墙
找到使用“输入正确”字符串的程序段,在0x44F13D。往前找,发现是用[esi+3010h]和立即数0xAD1C95B5比较,继续往前找,发现这个函数(在IDA距离视图中)上半部分实际上是一个巨大的switch(通过[esi+3010h]的不同取值分别跳往下方不同的程序段,执行完之后跳回顶端0x40A09B)。
40A574
然后接下来寻找某个程序段,在[esi+3010h]中放入了0xAD1C95B5使得程序转向显示输入正确的程序段执行,用IDA搜索这个数,找到只有0x44E753可能。
44E753
但是分析这一小段的逻辑,必须[esi+3053h]为最低位零 才可能执行到“输入正确”。寻找设置[esi+3053h]的程序段,发现还是只有一个0x44d170,比较0x401020的返回值和0x6e616b34(4kan)来设置[esi+3053h],然后这个401020函数传入的参数分别是0x65757832(2xue)、0和[esi+3024h]所指向的连续两个双字。
44D170
通过在循环开始位置断点,动调是哪一个程序段修改了此处,找到0x44C195
44C195
分析一下,发现输入的字符串的数字分割之后放在了0x49FE40数组中,然后这个0x44C195数次执行相当于从0x49F000数组中查出了以输入串的每一个数字为下标对应的值,并对它们求和。正好0x49F000这个数组大小是4*351字节(之后紧邻着2xue4kan)。

 

然后这个0x401020干了什么呢……查看调用列表发现__aullrem 64位的取模函数,查看调用发现取模数一直是0xFFA1CF8F,猜测这是一个类似哈希的算法。根据前面对[esi+3024h]的分析,这个函数的参数实际上是两个四字,第一个一直是0x65757832,第二个是0x44C195计算的和,动调发现调用取模函数前后主要在操作三个四字,观察它们的行为,包括平方、右移一位、求和,猜测这其实是一个快速幂取模函数。用各种参数测试一下。
发现
(0x65757832^n) % 0xffa1cf8f = 0x6E616B34
__aullrem
跑一个简单的脚本看看给0x401020什么参数会让结果是 ‘4kan’

long long mod = 0xffa1cf8f;
long long s0, ans = 0x65757832; s0 = ans;
    for (long long i = 2; i != 0xa00000000; i++) {
        ans = (ans*s0) % mod;
        if (ans == 0x6E616B34) printf("%lld %llx\n", i, i);

得到了一组数{ 0x055121c15, 0x154b3eba3, 0x25455bb31, 0x353f78abf, 0x453995a4d, 0x5533b29db, 0x652dcf969, 0x7527ec8f7, 0x852209885, 0x951c26813};

 

现在的问题就是从0x49f000数组中取出最多9个数和等于上面的这一组数。分析0x49f000这个数组,发现其中的每一个数都是{ 15825810, 138348210, 252282030, 329907270, 389890410, 612684930, 857758902, 1429598170, 2144397255 }的倍数,而且恰好(比如15825810这个数的1倍到270倍全部出现在0x49f000数组中)各自出现0到{ 270, 30, 16, 12, 10, 6, 4, 2, 1 }次。而且这组数刚好是9个,于是假设输入的数据经过0x44C195正好分别对应这9个因数的倍数,跑个脚本:

using namespace std;
#define FOR(A) for(t##A=0,sum-=ss[A];t##A<=c[A];t##A++,sum+=d[A])
#define HIDWORD(A) (*(((int *)(&A))+1))

int main() {
    clock_t t=clock();
    long long d[] = { 15825810, 138348210, 252282030, 329907270, 389890410, 612684930, 857758902, 1429598170, 2144397255 };//0x49f000中各数不同因子
    int    c[] = { 270, 30, 16, 12, 10, 6, 4, 2, 1 };//各种因子出现的范围
    long long ss[] = { 4288794510,4288794510,4288794510,4288794510,4288794510,4288794510,4288794510,4288794510,4288794510, };//(c[i]+1)*d[i] 优化用数组
    long long ans[] = { 0x055121c15, 0x154b3eba3, 0x25455bb31, 0x353f78abf, 0x453995a4d, 0x5533b29db, 0x652dcf969, 0x7527ec8f7, 0x852209885, 0x951c26813, };//可行解数组
    int  t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
    long long sum = 0;
    for (t9 = 0; t9 != 9; t9++) sum += ss[t9];
    FOR(0)    FOR(1)    FOR(2)
    FOR(3)    FOR(4)    FOR(5)
    FOR(6)    FOR(7)    FOR(8)
    {//0->8 0.600s 2.178s 8->0 2.593s 2.919s
        if (sum == ans[HIDWORD(sum)]) {
            printf("%d %d %d %d %d %d %d %d %d %d\n", t0, t1, t2, t3, t4, t5, t6, t7, t8, clock() - t);
        }
    }
    printf("%d",clock()-t);
    scanf("%d", &t);
    return 0;
}

这个的结果是【74 4 12 12 4 4 1 2 1】,将这个数组与d[]对应项相乘,然后转换成16进制到0x49f000查,得到的就是输入的数字了,排序之后就是序列号了
序列号


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回