BUGKU逆向reverse 1-8题

练习IDA两年半

打开尘封已久的bugku,从题目中练习使用,现在都已经是新版本了 orz
image.png

入门逆向

运行baby.exe
image.png
将解压后的baby.exe拖到IDA里面
image.png
主函数中找到mov指令 可以看到这里就是flag
image.png
flag{Re_1s_S0_C0OL}

signin

下载附件
image.png
解压之后是sign_in.apk ,Android逆向我不会啊orz
丢到AndroidKiller 里面去
可以看到这里有一个checkpassword方法
image.png
不过我不知道怎么把这个直接跳过 估计是需要登录的时候直接绕过这个方法然后重打包
看到评论里面有的人用的是GDK https://github.com/charles2gan/GDA-android-reversing-Tool

GDA,一款用C++实现的强大的Dalvik字节码反编译器,具有分析速度快、内存磁盘消耗低等优点,对apk、dex、odex、oat、jar、class、aar文件的反编译能力更强。

GDK打开之后 牛逼啊
image.png
登录验证逻辑如下

private String getFlag(){
   return this.getBaseContext().getString(0x7f0b0020);
}
private void showMsgToast(String p0){
   Toast.makeText(this, p0, 1).show();
}
public void checkPassword(String p0){
   if (p0.equals(new String(Base64.decode(this.getFlag().reverse(), 0)))) {
      this.showMsgToast("Congratulations !");
   }else {
      this.showMsgToast("Try again.");
   }
   return;
}

接下来去找这个0x7f0b0020对应的值是多少
转换成十进制为
image.png
去找2131427360 这玩意,不过我直接搜索这个值找不到
手动查toString 看到在这里
image.png
所以这个值对应的是toString
GDK用起来卡卡的
toString 的值为 991YiZWOz81ZhFjZfJXdwk3X1k2XzIXZIt3ZhxmZ
image.png
按照规则 把字符串逆序 ZmxhZ3tIZXIzX2k1X3kwdXJfZjFhZ18zOWZiY199
然后base64解密,得到flag
flag{Her3_i5_y0ur_f1ag_39fbc_}
image.png

Easy_Re

image.png
额要是我知道我还运行干啥
我理解这里应该是会有一个比较操作 逆向的时候在比较操作的时候看flag值
IDA打开之后F5查看伪代码
image.png
输入的内容存储到v7变量中 然后跟v5进行对比,对比结果存储到v3中

scanf("%s", v7);
v3 = strcmp(v5.m128i_i8, v7);

所以真实的flag就在v5中,赋值操作在

v5 = _mm_loadu_si128((const __m128i *)&xmmword_413E34);

真实值在 xmmword_413E34,点击跟进
image.png
按 a 转译
image.png
获取flag

游戏过关

运行exe,看起来这个游戏好难
image.png
n是灯的序列号,m是灯的状态
如果第N个灯的m为1,则它点亮,否则它熄灭
起初所有的灯都关上了
现在你可以输入n来改变它的状态
但你应该注意一件事,如果你改变第N个灯的状态,第(N-1)个和第(N+1)个的状态也会改变
当所有灯亮起时,flag将出现
现在,输入n

乱输一通
image.png
获得flag zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}
丢到IDA里面检查一下,这次的文件比较多 搜索flag字符串 alt+t
image.png
看到输出flag的界面
image.png
汇编代码如下
image.png
F5转换为C代码,去除掉一些干扰代码

int sub_45E940()
{
  int i; // [esp+D0h] [ebp-94h]
  char v2[22]; // [esp+DCh] [ebp-88h] BYREF
  char v3[32]; // [esp+F2h] [ebp-72h] BYREF
  char v4[4]; // [esp+112h] [ebp-52h] BYREF
  char v5[64]; // [esp+120h] [ebp-44h]

  sub_45A7BE("done!!! the flag is ");
  v5[0] = 18;
  v5[1] = 64;
  v5[2] = 98;
  v5[3] = 5;
  v5[4] = 2;
  v5[5] = 4;
  v5[6] = 6;
  v5[7] = 3;
  v5[8] = 6;
  v5[9] = 48;
  v5[10] = 49;
  v5[11] = 65;
  v5[12] = 32;
  v5[13] = 12;
  v5[14] = 48;
  v5[15] = 65;
  v5[16] = 31;
  v5[17] = 78;
  v5[18] = 62;
  v5[19] = 32;
  v5[20] = 49;
  v5[21] = 32;
  v5[22] = 1;
  v5[23] = 57;
  v5[24] = 96;
  v5[25] = 3;
  v5[26] = 21;
  v5[27] = 9;
  v5[28] = 4;
  v5[29] = 62;
  v5[30] = 3;
  v5[31] = 5;
  v5[32] = 4;
  v5[33] = 1;
  v5[34] = 2;
  v5[35] = 3;
  v5[36] = 44;
  v5[37] = 65;
  v5[38] = 78;
  v5[39] = 32;
  v5[40] = 16;
  v5[41] = 97;
  v5[42] = 54;
  v5[43] = 16;
  v5[44] = 44;
  v5[45] = 52;
  v5[46] = 32;
  v5[47] = 64;
  v5[48] = 89;
  v5[49] = 45;
  v5[50] = 32;
  v5[51] = 65;
  v5[52] = 15;
  v5[53] = 34;
  v5[54] = 18;
  v5[55] = 16;
  v5[56] = 0;

  qmemcpy(v2, "{ ", 2);
  v2[2] = 18;
  v2[3] = 98;
  v2[4] = 119;
  v2[5] = 108;
  v2[6] = 65;
  v2[7] = 41;
  v2[8] = 124;
  v2[9] = 80;
  v2[10] = 125;
  v2[11] = 38;
  v2[12] = 124;
  v2[13] = 111;
  v2[14] = 74;
  v2[15] = 49;
  v2[16] = 83;
  v2[17] = 108;
  v2[18] = 94;
  v2[19] = 108;
  v2[20] = 84;
  v2[21] = 6;
  
  for ( i = 0; i < 56; ++i )
  {
    v2[i] ^= v5[i];
    v2[i] ^= 0x13u;
  }
  return sub_45A7BE("%s\n");
}

这里有个问题啊,就是v2和v5的长度不一致
image.png
v2的长度就是22,这样的话最后得到的结果是
image.png
少了一部分的flag,但是v3和v4的长度加起来是 32+2=34,再加上前面的22就是56,所以我们应该把v2 v3 v4组在一起 为啥这里看不出来 我感觉这里的C语言代码是有点问题
更新python脚本

v2=[123,32,18,98,119,108,65,41,124,80,125,38,124,111,74,49,83,108,94,108,84,6,96,83,44,121,104,110,32,95,117,101,99,123,127,119,96,48,107,71,92,29,81,107,90,85,64,12,43,76,86,13,114,1,117,126,0]
v5=[18,64,98,5,2,4,6,3,6,48,49,65,32,12,48,65,31,78,62,32,49,32,1,57,96,3,21,9,4,62,3,5,4,1,2,3,44,65,78,32,16,97,54,16,44,52,32,64,89,45,32,65,15,34,18,16,0]
flag=""
for i in range(len(v2)):
    flag+=chr(v2[i]^v5[i]^0x13)

print(flag)

结果如下
image.png

换一个方式 使用动态调试 也就是掏出OllyDbg
使用中文搜索引擎
image.png
选择智能搜索 然后就可以看到
image.png
双击进入
image.png
这部分的入栈位置在这里
image.png
上转至 006A7AB4
image.png
上转调用位置为 006AF66C
image.png
这里的几个汇编指令我觉得需要解释一下
可以看到每一个jnz前面都有cmp,也就是比较失败就跳转到 006AF671
image.png
如果所有的比较都成功则调用call 方法,调用006A7AB4地址的方法
这里的逻辑很显然就是这里判断灯亮灯灭的判断(IDA中看见
image.png
所以我们将这里的jmp地址修改为call地址 不管输入 1-8 的哪个数字都能拿到flag了
image.png
image.png
右键复制到可执行文件 选择
image.png
保存为 ConsoleApplication7.exe,然后运行一下,输入 1,获取flag
image.png

Easy_vb

运行之后随便点点 好像没啥用
image.png
OD打开智能搜索
image.png

树林的小秘密

下载之后我的OD载入不了64位的程序 只能IDA了
shift + F12 搜索flag
image.png
看起来是pyinstaller打包的
image.png
用对应的工具去恢复源码,工具在这,点进去就是下载
https://nchc.dl.sourceforge.net/project/pyinstallerextractor/dist/pyinstxtractor.py

把工具和待反编译的exe放到一个目录下,然后运行

python pyinstxtractor.py easy_reverse.exe

image.png
生成了 easy_reverse.exe_extracted 文件,可以看到反编译的结果为
image.png
这里这个没有后缀的就是之前打包的python文件对应的pyc文件
这个时候打开123已经可以拿到flag了,base64解密
image.png
image.png

Timer(阿里CTF)

又是一个APK
GDA打开 搜索flag
image.png
跳转查看,如下
image.png
JNI编程?这么上流
image.png
这个位置load 了 so文件
image.png
所以其实flag在这个里面
image.png
但是so文件逆向我更不会了,只能看代码逻辑
初始化onCreate方法

protected void onCreate(Bundle savedInstanceState){
   super.onCreate(savedInstanceState);
   this.setContentView(R.layout.activity_main);
   Handler handler = new Handler();
   Runnable runnable = new MainActivity$1(this, this.findViewById(0x7f0c0051), this.findViewById(0x7f0c0050), handler);
   handler.postDelayed(runnable, 0);
}

运行了这个方法

public void run(){
   MainActivity$1 tthis$0;
   this.this$0.t = System.currentTimeMillis();
   this.this$0.now = (int)(this.this$0.t / 1000);
   this.this$0.t = 1500 - (this.this$0.t % 1000);
   this.val$tv2.setText("AliCTF");
   if (((this.this$0.beg - this.this$0.now)) <= 0) {
      this.val$tv1.setText("The flag is:");
      this.val$tv2.setText("alictf{"+this.this$0.stringFromJNI2(this.this$0.k)+"}");
   }
   if (MainActivity.is2((this.this$0.beg - this.this$0.now))) {
      tthis$0 = this.this$0;
      tthis$0.k = tthis$0.k + 100;
   }else {
      tthis$0 = this.this$0;
      tthis$0.k = tthis$0.k - 1;
   }
   this.val$tv1.setText("Time Remaining\(s\):"+(this.this$0.beg - this.this$0.now));
   this.val$handler.postDelayed(this, this.this$0.t);
   return;
}

OK 虽然看起来有点费劲
现在有四个参数

  • t
  • now
  • beg
  • k

now是当前时间戳
beg是启动APK的时候的时间,在
image.png
当然加了20万秒 所以如果破解不了的话就等着吧,虽然CTF比赛很快就要结束力
t 是一个取余时间值
k是计算的时间种子,最后会传到JNI方法里面去,所以我们如果直接改if语句是没用的,因为时间种子没有修改正确

所以这里我们有两个地方需要修改,一个是计算出正确的时间种子,一个是进入if语句,先从简单的进入if语句开始
image.png
把beg改成0就OK
不过好像GDK没有这个修改重打包的功能,使用AndroidKiller
image.png
把if-gtz修改为 if-lez,从判断大于零改为判断小于或等于零
接下来需要计算正确的K,抽离其中的关键因素
使用GDA反编译之后的代码看起来费劲,换成jd-gui
先使用dex2jar 把 classes.dex转换成 jd-gui可识别的jar包
image.png
然后使用jd-gui打开jar包,现在看起来就好多了
image.png
编写python脚本如下

now=0
beg=0+200000
k=0
def is2(n):
    if n<=3:
        if n > 1:
            return True
        return False
    elif n%2==0 or n%3==0:
        return False
    else:
        i=5
        while i*i <= n:
            if 0 == n%i or n%(i+2) == 0:
                return False
            i=i+6
        return True

while beg - now > 0:
    if is2(beg-now):
        k+=100
    else:
        k-=1
    beg -= 1

print(k)

运行得到K值
image.png
k值为 1616384
修改代码 在这里直接把K强行赋值
image.png
回编译得到修改后的APK
image.png
连一下自己手机
image.png
adb install之后运行 就可以看到flag了
a28b2a12db6814e473c870ace256c42.jpg
拿到flag

逆向入门

运行admin.exe???16位的应用程序
image.png
IDA打开感觉奇奇怪怪的,介素?
image.png
看起来类似010editer里面的格式,丢到wxmedit里面
一眼照片,这是逆向?服了
image.png
字符串丢到浏览器上 浏览器自动解码
image.png
扫码获取flag

OK现在逆向的前八题就做完了 再接再厉
image.png

END

建了一个微信的安全交流群,欢迎添加我微信备注进群,一起来聊天吹水哇,以及一个会发布安全相关内容的公众号,欢迎关注 😃

加我拉你入群 黑糖安全公众号
posted @ 2023-08-21 21:36  春告鳥  阅读(244)  评论(0编辑  收藏  举报