171022 逆向-Xp0intCTF(Re)

来源:互联网 发布:解决80端口被占用 编辑:程序博客网 时间:2024/06/07 22:54

1625-5 王子昂 总结《2017年10月22日》 【连续第387天总结】
A. Xpoint-暨南大学校赛
B.
今天有点晚了╮(╯_╰)╭推迟到零点结束,最后正好赶着把盲水印给搞定了
明天还有课,今天就先把Re的WP写好吧~明天有空的话写下misc的~
这次做题都忘了先查壳,还好一个壳都没有233

3倍

exe直接拖入IDA反编译
找不到入口点和关键函数,直接Shift+f12查找字符串
一眼就看到了Yes和No,双击进入IDA View
然后选中字符串,按x查看交叉引用,向上溯源到调用的地方:
这里写图片描述
再次双击,就来到了关键函数:
这里写图片描述
结构非常简单,就是接收int类型的输入,要求乘3后等于0x05C3F6EA
不过怎么说它也是个题目,要是真的一除就出来了也太简单了不是~

计算器计算一下,发现无法整除3

这个套路正好前两天在Reversing.kr上做过,轻车熟路
无法整除3怎么办?
说明真正得数不是0x05C3F6EA, 而是有部分值被溢出抛弃了
3*v5>2**64,溢出部分就没有记录了

那么穷举抛弃部分即可
python3脚本:

i = 1while(1):    p = i*0x100000000 + 0x5C3F6EA    if(p%3 == 0):        break    else:        i += 1print(p//3)

瞬间得到输出,提交给程序确认可以返回Yes

题目还提示要以字母形式输出,那么整数转字符用什么方法?当然是hex啦:
在原来的脚本上添加

print(bytes.fromhex(hex(p//3)[2:]))

即可

combo

下下来发现是个APK
拖入APK改之理或者AndroidKiller之类的反编译工具
在MainActivity中就能看到JAVA源码了:
这里写图片描述
函数很简单,Click事件要求点击201710次
当满足条件的时候将showFlag控件的文本改为2131099682
很明显这并不是flag,而是一个资源的id

这个类中没有相关的说明,我们再去别的类找找
然后在R.Class中查找到了对应的内容(逆向要善用Ctrl+F哦)
这里写图片描述
看到了变量名是galf,就是flag的逆序嘛,那么很明显关键的内容还藏着呢,接着找~

Class里看完了没有找到东西,我们去APK的整个资源里找一下呗
这里写图片描述
看,这样就搜索到了~

这种简单的方法仅针对字符串全部明码(硬编码)存放在数据中的

除此以外还可以动态调试APK,修改计数变量的值,令它直接改为201710就能显示flag了,相关过程我之前的总结有写过,就不再赘述了~

还有一种方法,就是直接修改源码,重新生成APK来运行
注意不能修改java源码哦,只能修改Android的汇编-Smali代码:
这里写图片描述
if(clkAcount==201710)的对应代码在这里
if-ne表示v0和v1不等的话就跳到cond_2处
v1在上一行进行了定义,v0在更上一行,可以看到就是clkAcount变量

爆破这行,将if-ne改为if-eq, 将v0改为v1等等方法都行,只要让它恒成立就OK了

保存后重新编译生成APK,安装运行,轻轻一点即可:
这里写图片描述

xor

这题就是最简单的入门题了
拖入IDA反编译,跟之前一样查找字符串-查看交叉引用
这里写图片描述
可以看出,Str1是接收输入的变量,之后与Str2进行比对,相同即通过
Str2来自于sub_411253的修改:
这里写图片描述
很简单,a1就是Str2的指针,相当于Str2[i] = i ^ data[i];
data是一个硬编码的数组,通过IDC脚本Dump出来脚本生成一下即可:
这里写图片描述
python3脚本:

d = [102, 109, 99, 100, 127, 99, 55, 117, 123, 125, 85, 120, 120, 104, 55, 46, 49, 108]for i in range(18):    print(chr(i ^ d[i]), end='')

密码生成器

这题稍微有点复杂了~
提示说是依靠时间生成的密码,只有一个不完整的源码

解压出来发现没有exe后缀名,用记事本/十六进制查看器打开发现文件头标识是ELF
说明是Linux下的可执行文件哦

先拖入IDA反编译吧
这次源码直接就在main函数中乖乖等我们看了呢
这里写图片描述

time.h相关的函数百度查一下就能得到说明
循环生成密码,可以看出来v8不断被赋值,应该就是密码了
所以说缺少的部分就是不打印了嘛╮(╯_╰)╭

注意这题有一个关键攻击点就是随机函数rand()
它其实是伪随机函数,程序依靠一个算法以srand(seed)的seed来建立一个序列,每次rand都会从中读出一个数字
换句话说,只要seed相同,rand读出的数字也会是完全相同的

这也是提示说密码生成来自时间的原因啦

具体算法不用太关心,直接复制粘贴到C++编译器里就行咯

为什么要用C++编译器而不用Python呢?
因为涉及随机数发生器,乱搞环境会出问题的呀!
(才不是因为我懒得把IDA的C++生成代码转成Python代码了呢~)

注意Byte*(i + 0x804A030)实际上就是指针+下标的数组访问法
因此byte_0x804A030数组还是要Dump出来,复制过去滴

#include <stdio.h>#include <stdlib.h>#include <time.h>//2017年10月13日22时08分57秒//linux的随机数序列不同,必须在linux下运行void main(){    time_t p;    struct tm* t;//时间结构体指针    int i;    int data[12]={33, 167, 153, 80, 119, 18, 35, 57, 97, 2, 160, 72};// 复制过来的数组    char v8[20]={0};    printf("%s\n", v8);    p = time(NULL);//得到现在时间    //printf("%d\n",p);    t = localtime(&p);//将时间转换成结构体    t->tm_year = 2017 - 1900;//按照提示中所给的时间写入    t->tm_mon = 10 - 1;    t->tm_mday = 13;    t->tm_hour = 22;    t->tm_min = 8;    t->tm_sec = 57;    p = mktime(t);//将结构体转换回秒数    printf("%d\n",p);    srand(p);//初始化随机数发生器  for ( i = 0; i <= 11; ++i )  {    for ( (v8[i]) = rand() % 80 + data[i];          (v8[i]) <= 64;          (v8[i]) += 26 )    {      ;    }    while ( (v8[i]) > 122 )      (v8[i]) -= 26;    if ( (v8[i]) > 90 && (v8[i]) <= 96 )      (v8[i]) -= 43;  }  printf("%s\n", v8);//输出密码    system("pause");}

代码运行好了以后生成的密码我怎么提交都不对,检查来检查去也没找到问题
最后想起来源程序是ELF格式的,可能在Linux环境下有所不同?
源码复制到虚拟机中gcc编译好了一运行,嘿,密码还真不一样~

提交,完成

so fun从提示来看应该是加壳了
我上次接触安卓加壳还是做前年的国赛的时候了……早就忘光啦,过两天有空再搞吧~

总体来说这次的难度适中,re300和re250稍微有些难度但还挺好玩儿的~
win下的re做起来渐渐也得心应手了呢
(ELF和Android的就要命了)

C. 明日计划
reversing.kr

原创粉丝点击