前言
过年的时候忘了,没打…….现在来复现复现 应该还是可以学到很多东西的
被and中级题搞到心态了
Windows
【2024春节】初级题1
找到输入的函数,flag的长度大概是36位
111111111111111111111111111111111111
直接动调出来了,flag在v7
fl@g{H@ppy_N3w_e@r!2o24!Fighting!!!}
Android
【2024春节】初级题1
难度不高,秒的题
在吾爱经常玩的小猫游戏,当然可以直接玩通关,但是出于逆向,还是逆一下吧
extractDataFromFile()方法就是游戏通关之后拿到的flag函数,是在后一个文件下进行检索 flag{ 字符然后输出到 } 字符,应该是上面的一个mp4的视频,flag应该在哪个文件十六进制的末尾处
hook代码
1 2 3 4 5
| Java.perform(function () { var YSQDActivity = Java.use("com.zj.wuaipojie2024_1.YSQDActivity"); var mmm = YSQDActivity.extractDataFromFile("/data/user/0/com.zj.wuaipojie2024_1/files/ys.mp4") console.log("返回结果是:",mmm) });
|
getflag:flag{happy_new_year_2024}
【2024春节】初级题2
也是一个类似的游戏题,达成某种条件后就可以getflag 这种题有一个通解就跟windows端的keypatch一样修改代码逻辑、数值从而达到想要的效果。下面是题目原图…..原神含量好足(虽然没玩过
简单分析一下函数的逻辑,反正就是真·保底……
再看一下flag生成的部分:
所以大体函数分析完成,之后就是如何getflag
1、可以直接去修改爆率或者判断的smile代码直接get flag 注意不要改签名信息就好
2、找到签名信息然后自己去异或 getflag
我就偏向于第一种吧,但是也先简单说说第二组。签名信息存储在main-inf的文件夹下的一个.rsa文件中,用ida查看16进制信息即可
mt做法:
0x50对应的是80,也就是上面的概率(假概率)本来是从80开始减,直接改成0,相当于直接百分百得到flag
在修改保存的时候一定不要自动签名,不然会改变签名信息导致flag错误
可以关掉签名校验安装,当然直接安也没什么问题
然后一次直接拿到flag,还是可以的
另外看佬的wp,发现了可以直接运行指定的activity
1
| adb shell su -c am start-activity -n com.kbtx.redpack_simple/.FlagActivity
|
直接弹flag的activity了,两个初级题同理直接秒了
【2024春节】中级题
打开apk运行一下,是一个类似于锁屏的一个控件
下面是正己师傅对于这段代码的详细解读,非常的详细
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
| public boolean checkPassword(String str) { try { InputStream open = getAssets().open("classes.dex"); byte[] bArr = new byte[open.available()]; open.read(bArr); File file = new File(getDir("data", 0), "1.dex"); FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(bArr); fileOutputStream.close(); open.close(); String str2 = (String) new DexClassLoader(file.getAbsolutePath(), getDir("dex", 0).getAbsolutePath(), null, getClass().getClassLoader()) .loadClass("com.zj.wuaipojie2024_2.C") .getDeclaredMethod("isValidate", Context.class, String.class, int[].class) .invoke(null, this, str, getResources().getIntArray(R.array.A_offset)); if (str2 == null || !str2.startsWith("唉!")) { return false; } this.tvText.setText(str2); this.myunlock.setVisibility(8); return true; } catch (Exception e) { e.printStackTrace(); return false; } }
public static String isValidate(Context context, String str, int[] iArr) throws Exception { try { return (String) getStaticMethod(context, iArr, "com.zj.wuaipojie2024_2.A", "d", Context.class, String.class).invoke(null, context, str); } catch (Exception e) { Log.e(TAG, "咦,似乎是坏掉的dex呢!"); e.printStackTrace(); return ""; } } private static Method getStaticMethod(Context context, int[] iArr, String str, String str2, Class<?>... clsArr) throws Exception { try { File fix = fix(read(context), iArr[0], iArr[1], iArr[2], context);
ClassLoader classLoader = context.getClass().getClassLoader();
File dir = context.getDir("fixed", 0);
Method declaredMethod = new DexClassLoader(fix.getAbsolutePath(), dir.getAbsolutePath(), null, classLoader) .loadClass(str) .getDeclaredMethod(str2, clsArr);
fix.delete(); new File(dir, fix.getName()).delete();
return declaredMethod; } catch (Exception e) { e.printStackTrace(); return null; } } private static File fix(ByteBuffer byteBuffer, int i, int i2, int i3, Context context) throws Exception { try { File dir = context.getDir("data", 0); int intValue = D.getClassDefData(byteBuffer, i).get("class_data_off").intValue(); HashMap<String, int[][]> classData = D.getClassData(byteBuffer, intValue); classData.get("direct_methods")[i2][2] = i3; byte[] encodeClassData = D.encodeClassData(classData); byteBuffer.position(intValue); byteBuffer.put(encodeClassData); byteBuffer.position(32); byte[] bArr = new byte[byteBuffer.capacity() - 32]; byteBuffer.get(bArr); byte[] sha1 = Utils.getSha1(bArr); byteBuffer.position(12); byteBuffer.put(sha1); int checksum = Utils.checksum(byteBuffer); byteBuffer.position(8); byteBuffer.putInt(Integer.reverseBytes(checksum)); byte[] array = byteBuffer.array(); File file = new File(dir, "2.dex"); FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(array); fileOutputStream.close(); return file; } catch (Exception e) { e.printStackTrace(); return null; } } 修复后的代码: public static String d(Context context, String str) { MainActivity.sSS(str); String signInfo = Utils.getSignInfo(context); if (signInfo == null || !signInfo.equals("fe4f4cec5de8e8cf2fca60a4e61f67bcd3036117")) { return ""; } StringBuffer stringBuffer = new StringBuffer(); int i = 0; while (stringBuffer.length() < 9 && i < 40) { int i2 = i + 1; String substring = "0485312670fb07047ebd2f19b91e1c5f".substring(i, i2); if (!stringBuffer.toString().contains(substring)) { stringBuffer.append(substring); } i = i2; }
return !str.equals(stringBuffer.toString().toUpperCase()) ? "" : "唉!哪有什么亿载沉睡的玄天帝,不过是一位被诅咒束缚的旧日之尊,在灯枯之际挣扎的南柯一梦罢了。有缘人,这份机缘就赠予你了。坐标在B.d"; } public static String d(String str) { return "机缘是{" + Utils.md5(Utils.getSha1("password+你的uid".getBytes())) + "}"; }
|
函数大致逻辑如下: 首先加载组件,然后根据组件的密码正确与否,进行一个判断
如果正确的话那就只输出,没啥用 如果错误的话,那就会运行checkPassword()方法
checkPassword方法首先会使用classes.dex生成一个1.dex
使用DexClassLoader方法去调取1.dex里面的方法
显示dex损坏或读取不到dex 自主修复1.dex,然后命名为2.dex
根据修复后的代码,修复B.d
Getflag
大致的函数过程如此,要想解决这个问题第一步还是修复dex
拖进010直接爆红,说明是文件头错误的dex,可以使用np修复,mt会修复全部的dex信息所以不太行
或者直接使用DexRepair
java -jar DexRepair.jar /path/to/dex
修复好了之后再压入到软件里面,最好是不要改变签名信息
修复了之后就可以正常走程序流程了,但是我怎么hook都报错
看报错貌似在so层有点问题
一直hook不到
好好好,原来是在so层加了frida检测
怪不得会有这个,自己找了找so,除此之外没找到什么so的作用,所以直接干脆不让他导入这个so得了 把这个so层的导入函数改成本地的空函数就行
变成了本地的空函数了,就不会再进行frida检测了
能hook上的(虽然但是………..捣鼓半天后用一个全新的附件来hook怎么也能hook上………..难道根本没调用吗?????逆天
算了无所谓,不去管了
现在的问题重点在于他在生成了1.dex后又删除了,所以我也想通过mt来删掉这个函数,mt删掉这两个参数
原来是读取文件…..就离谱 刚刚记得生成的是1.dex,但是这里是decode.dex,很明显读取不到 因为我没有装as(在虚拟机里,but虚拟机寄了)如果装了as那么就可以直接查看日志信息了 再去mt里面改改导入的dex名字
顺便把删除生成1.dex的方法给删掉
然后运行一下apk程序,果然他俩没有被删,先看看1在了什么
不用看了,搞不出来,好像题目一直有异常,都给我搞得怀疑人生了。。。。。
bmk佬说是题目附件的问题(真不知道是怎么一直触发异常的 于是借鉴了and_1师傅的思路-复现加密
以上可以忽略不看,是我个人的一些试错记录,我真不是水(bushi
复现加密
在idea单独起一个项目,用来复现加密流程,idea路径大致如下:
以下是代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
| import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.util.HashMap;
public class Main {
private static File fix(ByteBuffer byteBuffer, int v, int v1, int v2) throws Exception { File file = new File("./data"); int classDataOffset = (int) (((Integer) D.getClassDefData(byteBuffer, v).get("class_data_off"))); HashMap<String, int[][]> classData = D.getClassData(byteBuffer, classDataOffset); classData.get("direct_methods")[v1][2] = v2; byte[] encodedClassData = D.encodeClassData(classData); byteBuffer.position(classDataOffset); byteBuffer.put(encodedClassData); byteBuffer.position(0x20); byte[] data = new byte[byteBuffer.capacity() - 0x20]; byteBuffer.get(data); byte[] sha1 = Utils.getSha1(data); byteBuffer.position(12); byteBuffer.put(sha1); int checksum = Utils.checksum(byteBuffer); byteBuffer.position(8); byteBuffer.putInt(Integer.reverseBytes(checksum)); byte[] bufferData = byteBuffer.array(); File outputFile = new File(file, "2.dex"); FileOutputStream fileOutputStream = new FileOutputStream(outputFile); fileOutputStream.write(bufferData); fileOutputStream.close(); return outputFile; }
private static ByteBuffer readDex() { try { File inputFile = new File("./data/1.dex"); if (!inputFile.exists()) { System.out.printf("File does not exist."); return null; }
FileInputStream fileInputStream = new FileInputStream(inputFile); byte[] data = new byte[fileInputStream.available()]; fileInputStream.read(data); ByteBuffer byteBuffer = ByteBuffer.wrap(data); fileInputStream.close(); System.out.printf("\n File read successfully."); return byteBuffer; } catch (Exception ex) { return null; } }
public static void main(String[] args) throws Exception { ByteBuffer buf = readDex(); byte byteValue = buf.get(); char charValue = (char) byteValue; System.out.printf("%c", charValue); byteValue = buf.get(); charValue = (char) byteValue; System.out.printf("%c", charValue); byteValue = buf.get(); charValue = (char) byteValue; System.out.printf("%c", charValue);
File fixed = fix(buf, 0, 3, 7908); } } import java.math.BigInteger; import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList;
public class Utils { public static final String SHA1 = "SHA1";
public static byte[] toULEB128(int i) { int i2 = i >> 28; if (i2 > 0) { return new byte[]{(byte) ((i & 127) | 128), (byte) (((i >> 7) & 127) | 128), (byte) (((i >> 14) & 127) | 128), (byte) (((i >> 21) & 127) | 128), (byte) (i2 & 15)}; } int i3 = i >> 21; if (i3 > 0) { return new byte[]{(byte) ((i & 127) | 128), (byte) (((i >> 7) & 127) | 128), (byte) (((i >> 14) & 127) | 128), (byte) (i3 & 127)}; } int i4 = i >> 14; if (i4 > 0) { return new byte[]{(byte) ((i & 127) | 128), (byte) (((i >> 7) & 127) | 128), (byte) (i4 & 127)}; } int i5 = i >> 7; return i5 > 0 ? new byte[]{(byte) ((i & 127) | 128), (byte) (i5 & 127)} : new byte[]{(byte) (i & 127)}; }
public static byte[] getSha1(byte[] bArr) { try { return MessageDigest.getInstance("SHA").digest(bArr); } catch (Exception unused) { return null; } }
public static String md5(byte[] bArr) { try { String bigInteger = new BigInteger(1, MessageDigest.getInstance("md5").digest(bArr)).toString(16); for (int i = 0; i < 32 - bigInteger.length(); i++) { bigInteger = "0" + bigInteger; } return bigInteger; } catch (NoSuchAlgorithmException unused) { throw new RuntimeException("ops!!"); } }
public static int checksum(ByteBuffer byteBuffer) { byteBuffer.position(12); int capacity = byteBuffer.capacity(); int i = 1; int i2 = 0; boolean z = false; while (byteBuffer.position() < capacity) { ArrayList arrayList = new ArrayList(); int i3 = 0; while (true) { if (i3 < 1024) { arrayList.add(Integer.valueOf(byteBuffer.get() & 255)); if (byteBuffer.position() == byteBuffer.limit()) { z = true; break; } i3++; } else { break; } } int[] calculateVar = calculateVar(arrayList, i, i2); int i4 = calculateVar[0]; int i5 = calculateVar[1]; if (z) { return (i5 << 16) + i4; } i2 = i5; i = i4; } return 0; }
private static int[] calculateVar(ArrayList<Integer> arrayList, int i, int i2) { int i3 = 0; while (i3 < arrayList.size()) { int intValue = (arrayList.get(i3).intValue() + i) % 65521; i2 = (i2 + intValue) % 65521; i3++; i = intValue; } return new int[]{i, i2}; }
public static int[] fromULEB128(ByteBuffer byteBuffer) { int i; int i2 = byteBuffer.get() & 255; if (i2 > 127) { int i3 = byteBuffer.get() & 255; i2 = (i2 & 127) | ((i3 & 127) << 7); if (i3 > 127) { int i4 = byteBuffer.get() & 255; i2 |= (i4 & 127) << 14; if (i4 > 127) { int i5 = byteBuffer.get() & 255; i2 |= (i5 & 127) << 21; if (i5 > 127) { i2 |= (byteBuffer.get() & 255) << 28; i = 5; } else { i = 4; } } else { i = 3; } } else { i = 2; } } else { i = 1; } return new int[]{i2, i}; } } import java.nio.ByteBuffer; import java.util.HashMap;
public class D { private static byte[] decode_field(int[] arr_v, int v) { int v1 = arr_v[0] - v; int v2 = arr_v[1]; return D.merge(new byte[][]{Utils.toULEB128(v1), Utils.toULEB128(v2)}); }
private static byte[] decode_method(int[] arr_v, int v) { int v1 = arr_v[0] - v; int v2 = arr_v[1]; int v3 = arr_v[2]; return D.merge(new byte[][]{Utils.toULEB128(v1), Utils.toULEB128(v2), Utils.toULEB128(v3)}); }
public static byte[] encodeClassData(HashMap hashMap0) { int[][] arr2_v = (int[][])hashMap0.get("static_fields"); int[][] arr2_v1 = (int[][])hashMap0.get("instance_fields"); int[][] arr2_v2 = (int[][])hashMap0.get("direct_methods"); int[][] arr2_v3 = (int[][])hashMap0.get("virtual_methods"); byte[] arr_b = D.merge(new byte[][]{Utils.toULEB128(arr2_v.length), Utils.toULEB128(arr2_v1.length), Utils.toULEB128(arr2_v2.length), Utils.toULEB128(arr2_v3.length)}); if(arr2_v.length > 0) { int v = 0; int v1 = 0; while(v < arr2_v.length) { int[] arr_v = arr2_v[v]; arr_b = D.merge(new byte[][]{arr_b, D.decode_field(arr_v, v1)}); v1 = arr_v[0]; ++v; } }
if(arr2_v1.length > 0) { int v2 = 0; int v3 = 0; while(v2 < arr2_v1.length) { int[] arr_v1 = arr2_v1[v2]; arr_b = D.merge(new byte[][]{arr_b, D.decode_field(arr_v1, v3)}); v3 = arr_v1[0]; ++v2; } }
if(arr2_v2.length > 0) { int v4 = 0; int v5 = 0; while(v4 < arr2_v2.length) { int[] arr_v2 = arr2_v2[v4]; arr_b = D.merge(new byte[][]{arr_b, D.decode_method(arr_v2, v5)}); v5 = arr_v2[0]; ++v4; } }
if(arr2_v3.length > 0) { int v6 = 0; int v7 = 0; while(v6 < arr2_v3.length) { int[] arr_v3 = arr2_v3[v6]; arr_b = D.merge(new byte[][]{arr_b, D.decode_method(arr_v3, v7)}); v7 = arr_v3[0]; ++v6; } }
return arr_b; }
private static int[] encode_field(ByteBuffer byteBuffer0) { return new int[]{Utils.fromULEB128(byteBuffer0)[0], Utils.fromULEB128(byteBuffer0)[0]}; }
private static int[] encode_method(ByteBuffer byteBuffer0) { return new int[]{Utils.fromULEB128(byteBuffer0)[0], Utils.fromULEB128(byteBuffer0)[0], Utils.fromULEB128(byteBuffer0)[0]}; }
public static HashMap getClassData(ByteBuffer byteBuffer0, int v) { byteBuffer0.position(v); int v1 = Utils.fromULEB128(byteBuffer0)[0]; int v2 = Utils.fromULEB128(byteBuffer0)[0]; int v3 = Utils.fromULEB128(byteBuffer0)[0]; int v4 = Utils.fromULEB128(byteBuffer0)[0]; int[][] arr2_v = new int[v1][2]; if(v1 > 0) { int v5 = 0; int v6 = 0; while(v5 < v1) { int[] arr_v = D.encode_field(byteBuffer0); v6 = v5 == 0 ? arr_v[0] : v6 + arr_v[0]; arr2_v[v5] = new int[]{v6, arr_v[1]}; ++v5; } }
int[][] arr2_v1 = new int[v2][2]; if(v2 > 0) { int v7 = 0; int v8 = 0; while(v7 < v2) { int[] arr_v1 = D.encode_field(byteBuffer0); v8 = v7 == 0 ? arr_v1[0] : v8 + arr_v1[0]; arr2_v1[v7] = new int[]{v8, arr_v1[1]}; ++v7; } }
int[][] arr2_v2 = new int[v3][3]; if(v3 > 0) { int v9 = 0; int v10 = 0; while(v9 < v3) { int[] arr_v2 = D.encode_method(byteBuffer0); v10 = v9 == 0 ? arr_v2[0] : v10 + arr_v2[0]; arr2_v2[v9] = new int[]{v10, arr_v2[1], arr_v2[2]}; ++v9; } }
int[][] arr2_v3 = new int[v4][3]; if(v4 > 0) { int v11 = 0; int v12 = 0; while(v11 < v2) { int[] arr_v3 = D.encode_method(byteBuffer0); v12 = v11 == 0 ? arr_v3[0] : v12 + arr_v3[0]; arr2_v3[v11] = new int[]{v12, arr_v3[1], arr_v3[2]}; ++v11; } }
HashMap hashMap0 = new HashMap(); hashMap0.put("static_fields", arr2_v); hashMap0.put("instance_fields", arr2_v1); hashMap0.put("direct_methods", arr2_v2); hashMap0.put("virtual_methods", arr2_v3); return hashMap0; }
public static HashMap getClassDefData(ByteBuffer byteBuffer0, int v) { if(byteBuffer0 != null) { byteBuffer0.position(100); byteBuffer0.position(v * 0x20 + Integer.reverseBytes(byteBuffer0.getInt())); HashMap hashMap0 = new HashMap(); int v1 = Integer.reverseBytes(byteBuffer0.getInt()); int v2 = Integer.reverseBytes(byteBuffer0.getInt()); int v3 = Integer.reverseBytes(byteBuffer0.getInt()); int v4 = Integer.reverseBytes(byteBuffer0.getInt()); int v5 = Integer.reverseBytes(byteBuffer0.getInt()); int v6 = Integer.reverseBytes(byteBuffer0.getInt()); int v7 = Integer.reverseBytes(byteBuffer0.getInt()); int v8 = Integer.reverseBytes(byteBuffer0.getInt()); hashMap0.put("class_idx", Integer.valueOf(v1)); hashMap0.put("access_flag", Integer.valueOf(v2)); hashMap0.put("superclass_idx", Integer.valueOf(v3)); hashMap0.put("interfaces_off", Integer.valueOf(v4)); hashMap0.put("source_file_idx", Integer.valueOf(v5)); hashMap0.put("annotation_off", Integer.valueOf(v6)); hashMap0.put("class_data_off", Integer.valueOf(v7)); hashMap0.put("static_values_off", Integer.valueOf(v8)); return hashMap0; }
throw new IllegalArgumentException("Buffer cannot be null"); }
private static byte[] merge(byte[][] arr2_b) { int v = 0; int v1 = 0; while(v < arr2_b.length) { v1 += arr2_b[v].length; ++v; }
ByteBuffer byteBuffer0 = ByteBuffer.allocate(v1); int v2; for(v2 = 0; v2 < arr2_b.length; ++v2) { byteBuffer0.put(arr2_b[v2]); }
byte[] arr_b = new byte[byteBuffer0.position()]; byteBuffer0.position(0); byteBuffer0.get(arr_b); return arr_b; } }
|
(其实都是从安卓复制过来的然后修修报错能运行就问题不大了
最后也是终于获得了机缘