Loading... # Reverse(六) ## signin https://ctf.bugku.com/challenges/detail/id/136.html 这是一道安卓逆向题目,之前接触了一点点安卓逆向,但工具很不好用,用的手机模拟器里的MT管理器和NP管理器(都是操作安装包的工具,功能有些复杂还付费,感觉主要是用来破解挺不错的) 首先就是试下LOGIN看有什么反应,抓住关键词Try again去搜索找到在classes.dex(一般都是在这里,Java逻辑代码) <img src="http://xherlock.top/usr/uploads/2023/12/2454596741.png" alt="image-20231118191135870" style="zoom:50%;" style=""> 定位后在MainActivity里,还原smali为Java: <img src="http://xherlock.top/usr/uploads/2023/12/1413737263.png" alt="image-20231118191357416" style="zoom:50%;" style=""> 代码如下:关键在checkPassword函数里,先getFlag(),再反转,在base64解码输入;其中getFlag()的getBaseContext().getString(2131427360)这个不好确定 ~~~java // // Decompiled by Jadx (from NP Manager) // package re.sdnisc2018.sdnisc_apk1; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Base64; import android.widget.Button; import android.widget.Toast; public class MainActivity extends AppCompatActivity { public void checkPassword(String str) { if (str.equals(new String(Base64.decode(new StringBuffer(getFlag()).reverse().toString(), 0)))) { showMsgToast("Congratulations !"); } else { showMsgToast("Try again."); } } protected void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(2131296283); ((Button) findViewById(2131165261)).setOnClickListener(new 1(this)); } private String getFlag() { return getBaseContext().getString(2131427360); } private void showMsgToast(String str) { Toast.makeText(this, str, 1).show(); } } ~~~ 试图搜索数字搜不到,大概能猜到跟string有些关系,应该是存储在哪里了。看了别人的wp,要用jeb(1. https://down.52pojie.cn/Tools/Android_Tools/ 2. 安装jdk1.8.0 121,https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html) 具体使用方法: * 运行bat文件,打开apk文件 * 点击bytecode 点开结构层次即可看到主要类 ![image-20231118193622259.png](http://xherlock.top/usr/uploads/2023/12/3215252813.png) * 在某一类上按q即可反编译为java代码 去找前面出现的那串数字2131427360,定位如下(一个资源管理分配的id,id由R来管),toString是一个字符串,在string.xml中(values) ![image-20231118193917030.png](http://xherlock.top/usr/uploads/2023/12/689246228.png) ![image-20231118194502500.png](http://xherlock.top/usr/uploads/2023/12/2431151780.png) 复制,逆转,解码得flag {Her3_i5_y0ur_f1ag_39fbc_} ## 树木的小秘密 https://ctf.bugku.com/challenges/detail/id/355.html 本题考察的是pyinstaller的逆向(一个打包python程序为exe的程序) 逆向的代码:https://sourceforge.net/projects/pyinstallerextractor/,py文件 方法:python .\pyinstxtractor.py easy_reverse.exe,会在当前目录下生成easy_reverse.exe_extracted文件夹,进去发现如下 <img src="http://xherlock.top/usr/uploads/2023/12/643061814.png" alt="image-20231130203012864" style="zoom:50%;" style=""> wp告诉我去看123,里面有一串base64加密字符,后面告诉这是你的flag,解密得flag {my_name_is_shumu} ![image-20231130203153070.png](http://xherlock.top/usr/uploads/2023/12/1265079578.png) ## Timer(阿里CTF) https://ctf.bugku.com/challenges/detail/id/117.html 看图和代码意思是倒计时完才给你看flag(右图为jeb2逆向查看mainactivity) <img src="http://xherlock.top/usr/uploads/2023/12/2568236910.png" alt="image-20231130203914915" style="zoom:40%;" style=""><img src="http://xherlock.top/usr/uploads/2023/12/3798385042.png"" alt="image-20231130204154302" style="zoom:65%;" style=""> ![image-20231130204717992.png](http://xherlock.top/usr/uploads/2023/12/312582219.png) 关键是需要知道k值才能显示flag,timer为200000,每次now+1直到beg-now<0才显示答案,其中不能删除if来绕过因为k值需要在200000的过程中计算出来,因此需要求k(is2函数计算) ![image-20231130212025432.png](http://xherlock.top/usr/uploads/2023/12/2457109564.png) java代码模拟跑一下 ~~~java public class timer { public static boolean is2(int arg4) { boolean v1 = true; if(arg4 > 3) { if(arg4 % 2 != 0 && arg4 % 3 != 0) { int v0 = 5; while(true) { if(v0 * v0 <= arg4) { if(arg4 % v0 != 0 && arg4 % (v0 + 2) != 0) { v0 += 6; continue; } return false; } else { return v1; } } // return false; } v1 = false; } else if(arg4 <= 1) { v1 = false; } return v1; } public static void main(String[] args) { int beg = 200000, k = 0; while (beg>0) { if (is2(beg)) k += 100; else k--; beg--; } System.out.println(k); } } ~~~ ![image-20231130213321456.png](http://xherlock.top/usr/uploads/2023/12/1313208122.png) ### 安卓模拟器MT管理器反编译(操作有点麻烦) 得到k值为1616384,再去安卓模拟器的mt管理器编辑代码为该值(传入k前赋个值),注意定位到带dolar的那个源文件,里面才有run函数 ![image-20231130222443679.png](http://xherlock.top/usr/uploads/2023/12/122249898.png) 定位flag前面的if,删除它 ! ![image-20231130222700816](http://xherlock.top/usr/uploads/2023/12/850843135.png) 看不太清,但有答案了 alictf{Y0vAr3TimerMa3te7} ![image-20231130222942338](http://xherlock.top/usr/uploads/2023/12/1739383580.png) ### Androidkiller反编译(apktool老是反编译失败) 然后还要去除那个if条件判断直接显示,定位flag前的if,直接删除或者改成if-lez ![image-20231130214648663](http://xherlock.top/usr/uploads/2023/12/948727222.png) ![image-20231130214924947](http://xherlock.top/usr/uploads/2023/12/525052432.png) 如果编译失败的话:https://www.52pojie.cn/thread-887543-1-1.html,https://blog.csdn.net/pla12147111/article/details/95135104(删除1.apk),和apktool版本有关系 最后我的解决方法是换成apktool2.9(一开始就要这样用,不然前后编译不一致报错),编译完成后最底下有新的apk路径 ![image-20231201110140666](http://xherlock.top/usr/uploads/2023/12/2839500839.png) 模拟器打开即可看到flag ## mobile1(gctf) https://ctf.bugku.com/challenges/detail/id/137.html 首先jeb2查看mainactivity反编译的java主函数代码:结合 ![image-20231201131839587](http://xherlock.top/usr/uploads/2023/12/4164252128.png) 结合app具体界面报错“错误”关键词去搜索strings.xml, ![image-20231201131938006](http://xherlock.top/usr/uploads/2023/12/2805612823.png) 搜到name,再去搜R类下的id,id16进制转10进制值为2131099678,定位代码可以看出关键逻辑代码为onclick里的if判断 ![image-20231201132023554](http://xherlock.top/usr/uploads/2023/12/1847918179.png) 关注checkSN函数,第一个参数为用户名Tenshine,第二个为输入的密码,关键是返回True ~~~java private boolean checkSN(String arg11, String arg12) { boolean v7 = false; if(arg11 != null) { try { if(arg11.length() == 0) { return v7; } if(arg12 == null) { return v7; } if(arg12.length() != 22) { return v7; // 密码长22位 } MessageDigest v1 = MessageDigest.getInstance("MD5"); v1.reset(); v1.update(arg11.getBytes()); // md5加密用户名 String v3 = MainActivity.toHexString(v1.digest(), ""); // 转为16进制 StringBuilder v5 = new StringBuilder(); int v4; for(v4 = 0; v4 < v3.length(); v4 += 2) { v5.append(v3.charAt(v4)); // 每两个取一次字符 } if(!"flag{" + v5.toString() + "}".equalsIgnoreCase(arg12)) { return v7; } } catch(NoSuchAlgorithmException v2) { goto label_40; } v7 = true; } return v7; label_40: v2.printStackTrace(); return v7; } ~~~ 写个python脚本解密 ~~~python import hashlib md5_object = hashlib.md5() md5_object.update(b'Tenshine') md5_result = md5_object.hexdigest() print(md5_result) for i in range(0, len(md5_result), 2): print(md5_result[i], end="") ~~~ 结果为bc72f242a6af3857,带上即为flag{bc72f242a6af3857} ## First_Mobile(xman) https://ctf.bugku.com/challenges/detail/id/139.html 过于简单,一个脚本即可算出值。jeb查看OnCreate的核心函数 ![image-20231201160417218](http://xherlock.top/usr/uploads/2023/12/2232608028.png) 双击查看encode函数 ![image-20231201160448106](http://xherlock.top/usr/uploads/2023/12/66736227.png) python脚本求解:得到LOHILMNMLKHILKHI ~~~python b = [23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 30, 30, 29, 30, 32, 32] for i in range(16): for j in range(128): if (j + b[i]) % 61 * 2 - i == j: print(chr(j), end="") ~~~ ## 马老师杀毒卫士 https://ctf.bugku.com/challenges/detail/id/145.html?id=145&page=2 栅栏密码加密,在strings里的,不看wp我都不知道这么多字符串咋找的 ![image-20231201162144151](http://xherlock.top/usr/uploads/2023/12/2043836498.png) <img src="http://xherlock.top/usr/uploads/2023/12/1354621362.png" alt="image-20231201162430960" style="zoom:67%;" style=""> ## NoString https://ctf.bugku.com/challenges/detail/id/229.html 打开测试发现如下: ![image-20231201163218675](http://xherlock.top/usr/uploads/2023/12/93672977.png) ida查找字符串找不到,估计混淆了,和题目有些相呼应,搜main伪代码,发现如下,基本可以猜到error变体为了l{{f{,逻辑代码就是这个 ~~~c int wmain() { signed int v0; // ecx signed int i; // eax signed int v2; // ecx signed int j; // eax int k; // eax int v5; // eax signed int v6; // ecx signed int m; // eax signed int v8; // ecx signed int n; // eax char v11; // [esp+0h] [ebp-18h] BYREF __int128 v12; // [esp+1h] [ebp-17h] __int16 v13; // [esp+11h] [ebp-7h] v0 = strlen(Format); for ( i = 0; i < v0; ++i ) Format[i] ^= 9u; printf("yelhzl)`gy|})|)oehnl3"); v11 = 0; v13 = 0; v12 = 0i64; v2 = strlen(a80z); for ( j = 0; j < v2; ++j ) a80z[j] ^= 9u; scanf(a80z, &v11); // 赋值给v11 for ( k = 0; k < 19; ++k ) *(&v11 + k) ^= 9u; // v11加密 v5 = strcmp(&v11, aOehnl3rHfCcgpt); // 和这个变量比较,双击查看值为oehnl3r=<?=hF@CCGPt,可以利用异或特点求得v11 if ( v5 ) v5 = v5 < 0 ? -1 : 1; if ( v5 ) { v6 = strlen(aLF); for ( m = 0; m < v6; ++m ) aLF[m] ^= 9u; printf("l{{f{"); // error的混淆 } else { v8 = strlen(aNa); for ( n = 0; n < v8; ++n ) aNa[n] ^= 9u; printf("{`na}"); } printf("\r\n"); system("pause"); // 最后退出 return 0; } ~~~ python脚本如下:得到flage:{4564aOIJJNY} ~~~python s = "oehnl3r=<?=hF@CCGPt" for i in range(len(s)): print(chr(ord(s[i])^9), end="") ~~~ ## ez fibon https://ctf.bugku.com/challenges/detail/id/280.html exeinfo发现有壳,用upd解下壳 ![image-20231201165012136](http://xherlock.top/usr/uploads/2023/12/688521780.png) ![image-20231201165007417](http://xherlock.top/usr/uploads/2023/12/3398948705.png) ida定位具体代码,分析后发现其实是做了个混淆,实际功能很简单 ~~~c int __fastcall main(int argc, const char **argv, const char **envp) { int v3; // edx int v5[24]; // [rsp+20h] [rbp-60h] char Str[524]; // [rsp+80h] [rbp+0h] BYREF int j; // [rsp+28Ch] [rbp+20Ch] int v8; // [rsp+290h] [rbp+210h] int v9; // [rsp+294h] [rbp+214h] int i; // [rsp+298h] [rbp+218h] int v11; // [rsp+29Ch] [rbp+21Ch] _main(); v11 = 1; puts("please input your flag:"); gets(Str); for ( i = 0; i <= 21; ++i ) *(_DWORD *)&Str[4 * i + 112] = Str[i]; if ( strlen(Str) == 22 ) // 长度必须为22 { // 斐波那契数列 v8、v9 v9 = 1; v8 = 1; for ( j = 0; j <= 21; ++j ) { if ( (j & 1) != 0 ) // j为奇数 { v8 += v9; v3 = (v8 + j + *(_DWORD *)&Str[4 * j + 112]) % 64 + 64; } else // j为偶数 { v9 += v8; v3 = (v9 + j + *(_DWORD *)&Str[4 * j + 112]) % 64 + 64; } *(_DWORD *)&Str[4 * j + 112] = v3; } v5[0] = 100; v5[1] = 121; v5[2] = 110; v5[3] = 118; v5[4] = 70; v5[5] = 85; v5[6] = 123; v5[7] = 109; v5[8] = 64; v5[9] = 94; v5[10] = 109; v5[11] = 99; v5[12] = 116; v5[13] = 81; v5[14] = 109; v5[15] = 86; v5[16] = 83; v5[17] = 126; v5[18] = 119; v5[19] = 101; v5[20] = 110; v5[21] = 114; for ( j = 0; j <= 21; ++j ) { if ( v5[j] != *(_DWORD *)&Str[4 * j + 112] ) v11 = 0; } if ( !v11 ) printf("wrong!"); if ( v11 == 1 ) printf("right flag!"); } else { printf("wrong lenth!"); } return 0; } ~~~ python脚本解密:得到bugku{So_Ez_Fibon@cci} ~~~python fib = [2, 3] k = 2 while len(fib) <= 22: fib.append(fib[k-1]+fib[k-2]) k += 1 s = [100, 121, 110, 118, 70, 85, 123, 109, 64, 94, 109, 99, 116, 81, 109, 86, 83, 126, 119, 101, 110, 114] for i in range(len(s)): print(chr((s[i]-i-fib[i]+64)%64+64), end="") ~~~ ## LoopAndLoop(阿里CTF) https://ctf.bugku.com/challenges/detail/id/120.html jeb查看MainAcitivity,关键函数为check ~~~c++ public class MainActivity extends AppCompatActivity { static { System.loadLibrary("lhm"); } public MainActivity() { super(); } public native int chec(int arg1, int arg2) { } public int check(int arg2, int arg3) { return this.chec(arg2, arg3); } public int check1(int arg4, int arg5) { int v1 = arg4; int v0; for(v0 = 1; v0 < 100; ++v0) { v1 += v0; } return this.chec(v1, arg5); } public int check2(int arg5, int arg6) { int v2; int v3 = 1000; int v1 = arg5; if(arg6 % 2 == 0) { int v0; for(v0 = 1; v0 < v3; ++v0) { v1 += v0; } v2 = this.chec(v1, arg6); } else { for(v0 = 1; v0 < v3; ++v0) { v1 -= v0; } v2 = this.chec(v1, arg6); } return v2; // 这里是唯一返回不是函数而是值,照应最后一个1是模3为1 } public int check3(int arg4, int arg5) { int v1 = arg4; int v0; for(v0 = 1; v0 < 10000; ++v0) { v1 += v0; } return this.chec(v1, arg5); } public String messageMe(String arg3) { return "LoopOk" + arg3; } protected void onCreate(Bundle arg6) { super.onCreate(arg6); this.setContentView(2130968600); this.findViewById(2131492946).setOnClickListener(new View$OnClickListener(this.findViewById(2131492944), this.findViewById(2131492945), this.findViewById(2131492947)) { public void onClick(View arg7) { int v1; String v2 = this.val$ed.getText().toString(); try { v1 = Integer.parseInt(v2); // 要求必须是整型数字 } catch(NumberFormatException v0) { this.val$tv1.setText("Not a Valid Integer number"); return; } if(MainActivity.this.check(v1, 99) == 1835996258) { // 关键点,v1是输入的数字 this.val$tv1.setText("The flag is:"); this.val$tv2.setText("alictf{" + MainActivity.this.stringFromJNI2(v1) + "}"); } else { this.val$tv1.setText("Not Right!"); } } }); } public boolean onCreateOptionsMenu(Menu arg3) { this.getMenuInflater().inflate(2131558400, arg3); return 1; } public boolean onOptionsItemSelected(MenuItem arg3) { boolean v1 = arg3.getItemId() == 2131492961 ? true : super.onOptionsItemSelected(arg3); return v1; } public native String stringFromJNI2(int arg1) { } } ~~~ 这题难点在于代码都在native层(c代码),无法直接看到,要用提取出来用ida分析函数 <img src="http://xherlock.top/usr/uploads/2023/12/1742711442.png" alt="image-20231201184109781" style="zoom:67%;" style=""> ida定位并跳转伪代码 ![image-20231201185013114](http://xherlock.top/usr/uploads/2023/12/3937410819.png) 感觉我java/c++学得好烂啊,这些都没学过,和JNI有关(Java Native Interface) ~~~c int __fastcall Java_net_bluelotus_tomorrow_easyandroid_MainActivity_chec(int a1, int a2, int a3, int a4) { int v5; // r7 int v10[9]; // [sp+1Ch] [bp-24h] BYREF v5 = (*(int (__fastcall **)(int, const char *))(*(_DWORD *)a1 + 24))( a1, "net/bluelotus/tomorrow/easyandroid/MainActivity"); v10[0] = _JNIEnv::GetMethodID(a1, v5, "check1", "(II)I"); // 三种调用方法,方法在MainActivity里 v10[1] = _JNIEnv::GetMethodID(a1, v5, "check2", "(II)I"); // 第三个表示java里的函数名,第四个括号里表示两个INT参数,括号外表示返回类型参数 v10[2] = _JNIEnv::GetMethodID(a1, v5, "check3", "(II)I"); // 前两个参数实在晕,但可以确定的是和调用的函数参数无关 if ( a4 - 1 <= 0 ) return a3; else return _JNIEnv::CallIntMethod(a1, a2, v10[2 * a4 % 3], a3, a4 - 1); // v10里的是具体选哪个方法 } // a3是第一个参数,a4-1是第二个参数,由此可见每次第二个参数都要-1 ~~~ 具体的逻辑就是,初始check下的chec的a4为99,选择了check1,check1里又去做了一次chec,这时a4为98(在c代码中减了1),然后直到a4-1<=0即a4=0为止 需要做的是逆向java里的三个check函数,使得最终值为1835996258,因此逆向初始值为1835996258 ~~~python def check1(a1, a2): for i in range(1, 100): a1 -= i return a1 def check2(a1, a2): if a2 % 2 == 0: for i in range(1, 1000): a1 -= i else: for i in range(1, 1000): a1 += i return a1 def check3(a1, a2): for i in range(1, 10000): a1 -= i return a1 if __name__ == '__main__': k = 1835996258 for i in range(2, 100): if i * 2 % 3 == 0: k = check1(k, i-1) elif i * 2 % 3 == 1: k = check2(k, i-1) else: k = check3(k, i-1) print(k) ~~~ 运行脚本得到236492408,app运行后输入即可得到flag ### 小结 本题是逆向到现在感觉最复杂的题目,难点不在于写脚本啥的,而是真正去理解逆向的思维,举例来说 * 首先要懂得反编译(jeb)查找主要Java逻辑代码,并基本读懂 * 接着要理解native(JNI)的原理,提取库文件,用ida分析 * 到了ida还要懂得定位调用的地方,结合java代码分析 * 最后理解了这些,还要写代码逆向回去,代码中如果出现多个循环,很容易搞错开始和结束的条件 此外还看到题目下面一个评论,思路好强!不用写代码,让他自己计算,得到差值即可(我没有去验证) ![image-20231201203431150.png](http://xherlock.top/usr/uploads/2023/12/2139655925.png) 最后修改:2023 年 12 月 14 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏