# Another Android Applaketion下载附件发现是 apk 文件,拖入 jadx 打开,然后找到 MainActivity:
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 package com.lake.ctf; import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.LinearLayout;import android.widget.TextView;public class MainActivity extends AppCompatActivity { long wow = 0 ; public native long Init(); public native bool ean Test(String str); static { System.loadLibrary("ohgreat2" ); } @Override protected void onCreate(Bundle bundle) { super .onCreate(bundle); this .wow = Init(); LinearLayout linearLayout = new LinearLayout(this ); linearLayout.setOrientation(1 ); final TextView textView = new TextView(this ); textView.setText("this UI follows swiss style" ); final EditText editText = new EditText(this ); editText.setHint("Enter flag:" ); Button button = new Button(this ); button.setText("Check flag" ); button.setOnClickListener(new View.OnClickListener() { @Override public final void onClick(View view) { this .f$0. m4lambda$onCreate$0 $comlakectfMainActivity(editText, textView, view); } }); linearLayout.addView(editText); linearLayout.addView(button); linearLayout.addView(textView); setContentView(linearLayout); } void m4lambda$onCreate$0 $comlakectfMainActivity(EditText editText, TextView textView, View view) { String string = editText.getText().toString(); Log.i("LAKECTF" , "flag: " + string ); if (string .length() != 55 ) { textView.setText("flag is wrong..." ); return ; } bool ean zTest = Test(string ); bool ean zTest2 = Test(string ); bool ean zTest3 = Test(string ); bool ean zTest4 = Test(string ); bool ean zTest5 = Test(string ); bool ean zTest6 = Test(string ); bool ean zTest7 = Test(string ); bool ean zTest8 = Test(string ); bool ean zTest9 = Test(string ); bool ean zTest10 = Test(string ); bool ean zTest11 = Test(string ); bool ean zTest12 = Test(string ); bool ean zTest13 = Test(string ); bool ean zTest14 = Test(string ); bool ean zTest15 = Test(string ); bool ean zTest16 = Test(string ); bool ean zTest17 = Test(string ); bool ean zTest18 = Test(string ); bool ean zTest19 = Test(string ); bool ean zTest20 = Test(string ); bool ean zTest21 = Test(string ); bool ean zTest22 = Test(string ); bool ean zTest23 = Test(string ); bool ean zTest24 = Test(string ); bool ean zTest25 = Test(string ); bool ean zTest26 = Test(string ); bool ean zTest27 = Test(string ); bool ean zTest28 = Test(string ); bool ean zTest29 = Test(string ); bool ean zTest30 = Test(string ); bool ean zTest31 = Test(string ); bool ean zTest32 = Test(string ); bool ean zTest33 = Test(string ); bool ean zTest34 = Test(string ); bool ean zTest35 = Test(string ); bool ean zTest36 = Test(string ); bool ean zTest37 = Test(string ); bool ean zTest38 = Test(string ); bool ean zTest39 = Test(string ); bool ean zTest40 = Test(string ); bool ean zTest41 = Test(string ); bool ean zTest42 = Test(string ); bool ean zTest43 = Test(string ); bool ean zTest44 = Test(string ); bool ean zTest45 = Test(string ); bool ean zTest46 = Test(string ); bool ean zTest47 = Test(string ); bool ean zTest48 = Test(string ); bool ean zTest49 = Test(string ); bool ean zTest50 = Test(string ); bool ean zTest51 = Test(string ); bool ean zTest52 = Test(string ); bool ean zTest53 = Test(string ); bool ean zTest54 = Test(string ); bool ean zTest55 = Test(string ); bool ean zTest56 = Test(string ); bool ean zTest57 = Test(string ); bool ean zTest58 = Test(string ); bool ean zTest59 = Test(string ); bool ean zTest60 = Test(string ); bool ean zTest61 = Test(string ); bool ean zTest62 = Test(string ); bool ean zTest63 = Test(string ); bool ean zTest64 = Test(string ); bool ean zTest65 = Test(string ); bool ean zTest66 = Test(string ); bool ean zTest67 = Test(string ); bool ean zTest68 = Test(string ); bool ean zTest69 = Test(string ); bool ean zTest70 = Test(string ); bool ean zTest71 = Test(string ); bool ean zTest72 = Test(string ); bool ean zTest73 = Test(string ); bool ean zTest74 = Test(string ); bool ean zTest75 = Test(string ); bool ean zTest76 = Test(string ); bool ean zTest77 = Test(string ); bool ean zTest78 = Test(string ); bool ean zTest79 = Test(string ); bool ean zTest80 = Test(string ); if (zTest && zTest2 && zTest3 && zTest4 && zTest5 && zTest6 && zTest7 && zTest8 && zTest9 && zTest10 && zTest11 && zTest12 && zTest13 && zTest14 && zTest15 && zTest16 && zTest17 && zTest18 && zTest19 && zTest20 && zTest21 && zTest22 && zTest23 && zTest24 && zTest25 && zTest26 && zTest27 && zTest28 && zTest29 && zTest30 && zTest31 && zTest32 && zTest33 && zTest34 && zTest35 && zTest36 && zTest37 && zTest38 && zTest39 && zTest40 && zTest41 && zTest42 && zTest43 && zTest44 && zTest45 && zTest46 && zTest47 && zTest48 && zTest49 && zTest50 && zTest51 && zTest52 && zTest53 && zTest54 && zTest55 && zTest56 && zTest57 && zTest58 && zTest59 && zTest60 && zTest61 && zTest62 && zTest63 && zTest64 && zTest65 && zTest66 && zTest67 && zTest68 && zTest69 && zTest70 && zTest71 && zTest72 && zTest73 && zTest74 && zTest75 && zTest76 && zTest77 && zTest78 && zTest79 && zTest80) { textView.setText("flag correct!" ); } else { textView.setText("flag is wrong..." ); } } }
分析可知:
Flag 的长度固定为 55 个字符;
System.loadLibrary ("ohgreat2"); 说明核心逻辑在名为 libohgreat2.so 的 C/C++ 动态库中;
this.wow = Init (); 在应用启动时调用了一个 Init 函数;
有一个奇怪的 80 次调用 :
1 2 3 4 boolean zTest = Test(string );boolean zTest2 = Test(string );if (zTest && zTest2 && ... && zTest80) { Success }
你输入了同一个字符串 string,但程序调用了 80 次 Test (string),并且要求每一次都必须返回 true。 因此找到 libohgreat2.so 文件,拖入 ida 中,找到 Java_com_lake_ctf_MainActivity_Test 函数:
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 __int64 __fastcall Java_com_lake_ctf_MainActivity_Test(__int64 a1, __int64 a2, int a3){ char *v5; char *v6; __int64 v7; int v8; int v9; int v10; _OWORD v12[16 ]; _OWORD v13[16 ]; unsigned __int64 v14; v14 = __readfsqword (0 x28u); memset(v13, 0 , sizeof (v13)); v5 = (char *)__strcat_chk (v13, "com/lake/ctf/Check" , 256 ); strcat(v5, aaa); memset(v12, 0 , sizeof (v12)); v6 = (char *)__strcat_chk (v12, "Check" , 256 ); strcat(v6, bbb); v7 = (*(__int64 (__fastcall **)(__int64 , _OWORD *))(*(_QWORD *)a1 + 48 LL))(a1, v13); v8 = (*(__int64 (__fastcall **)(__int64 , __int64 , _OWORD *, const char *))(*(_QWORD *)a1 + 904 LL))( a1, v7, v12, "(Ljava/lang/String;)Z" ); return _JNIEnv ::CallStaticBooleanMethod(a1, v7, v8, a3, v9, v10, v12[0 ]); }
分析可知
Init 函数:把两个全局变量 aaa 和 bbb 设置为了两个很长的十六进制字符串。 Test 函数:把这俩字符串拼接到类名和方法名后面,然后通过反射去调用 Java 方法。 然后再 jadx 可以看见许多 check 函数
因此导出所有 Java 代码
然后通过 z3-solver 写脚本即可求解:
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 import osimport refrom z3 import *SOURCE_DIR = r"D:\1\com.lake.ctf" def solve (): print (f"[*] 正在扫描文件夹: {SOURCE_DIR} ..." ) methods = {} class_pattern = re.compile (r'Check([a-f0-9]{64})' ) method_pattern = re.compile ( r'static boolean Check([a-f0-9]{64})\(String \w+\)\s*\{' r'\s*if \((.*?)\)\s*\{' r'\s*nop\("([a-f0-9]{64})", "([a-f0-9]{64})"' , re.DOTALL | re.MULTILINE ) file_count = 0 for root, dirs, files in os.walk(SOURCE_DIR): for file in files: if file.endswith(".java" ) and file.startswith("Check" ): file_count += 1 path = os.path.join(root, file) try : with open (path, 'r' , encoding='utf-8' , errors='ignore' ) as f: content = f.read() class_match = class_pattern.search(file) if not class_match: continue current_class_hash = class_match.group(1 ) if current_class_hash not in methods: methods[current_class_hash] = {} for m in method_pattern.findall(content): m_hash, cond, next_cls, next_mtd = m methods[current_class_hash][m_hash] = (cond, next_cls, next_mtd) except Exception as e: print (f"[-] 读取文件 {file} 出错: {e} " ) print (f"[*] 扫描完成,共处理 {file_count} 个文件。" ) print (f"[*] 加载了 {len (methods)} 个类的信息。" ) curr_class = "86e50149658661312a9e0b35558d84f6c6d3da797f552a9657fe0558ca40cdef" curr_method = "031b4af5197ec30a926f48cf40e11a7dbc470048a21e4003b7a3c07c5dab1baa" constraints = [] print ("[*] 正在追踪 80 层调用链..." ) for i in range (80 ): if curr_class not in methods: print (f"[-] 错误:找不到类 Hash {curr_class[:8 ]} ... (链条在第 {i + 1 } 步断裂)" ) break if curr_method not in methods[curr_class]: print (f"[-] 错误:在类 {curr_class[:8 ]} ... 中找不到方法 {curr_method[:8 ]} ..." ) break cond, next_cls, next_mtd = methods[curr_class][curr_method] constraints.append(cond) curr_class = next_cls curr_method = next_mtd print (f"[*] 成功收集到 {len (constraints)} 个方程约束。正在使用 Z3 求解..." ) solver = Solver() flag_chars = [Int(f'x_{i} ' ) for i in range (55 )] for i in range (55 ): solver.add(flag_chars[i] >= 32 , flag_chars[i] <= 126 ) for raw_cond in constraints: py_expr = re.sub(r'str\.charAt\((\d+)\)' , r'x_\1' , raw_cond) if "==" in py_expr: left, right = py_expr.split('==' ) env = {f'x_{i} ' : flag_chars[i] for i in range (55 )} try : solver.add(eval (left, {}, env) == int (right)) except Exception as e: print (f"[-] 解析方程失败: {raw_cond} -> {e} " ) if solver.check() == sat: model = solver.model() flag_str = "" for i in range (55 ): val = model[flag_chars[i]] if val is not None : flag_str += chr (val.as_long()) else : flag_str += "?" print ("\n" + "=" * 50 ) print (f"🎉 恭喜!Flag 是:\n{flag_str} " ) print ("=" * 50 + "\n" ) else : print ("[-] 无解 (Unsatisfiable)。可能文件导出不完整或逻辑解析有误。" ) if __name__ == "__main__" : solve()
运行得到 EPFL {Wh1_3v3n_b0th3r_w1th_J4v4_1n_th3_f1rst_Pl4c3?????}
# drum machine通过 ida 分析 main 函数,可以知道:
读取用户输入字符串。
调用 decomposeInput 将字符串转换为 vector<Step>。
初始化 DrumMachine 对象(加载巨大的转移表)。
调用 DrumMachine::playBeat 执行状态机。
检查 DrumMachine::getState () == 181。如果成立,打印 "Congratulations"。
同时 main 函数还定义了字符到状态机输入的转换规则:
因此可以知道这是一个典型的 DFA (确定性有限自动机) 实现。 转移表硬编码在 DrumMachine 的构造函数中
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 void __fastcall DrumMachine::DrumMachine(DrumMachine *this , __int64 a2) { _DWORD *v2; std::vector<Step>::vector(this , a2); v2 = (_DWORD *)((char *)this + 24 ); memset(v2, 0 , 0x1700u); *v2 = 1 ; *((_DWORD *)this + 15 ) = 1 ; *((_DWORD *)this + 16 ) = 2 ; *((_DWORD *)this + 25 ) = 2 ; *((_DWORD *)this + 26 ) = 4 ; *((_DWORD *)this + 27 ) = 5 ; *((_DWORD *)this + 28 ) = 3 ; *((_DWORD *)this + 30 ) = 6 ; *((_DWORD *)this + 31 ) = 3 ; *((_DWORD *)this + 32 ) = 3 ; *((_DWORD *)this + 34 ) = 4 ; *((_DWORD *)this + 37 ) = 6 ; *((_DWORD *)this + 43 ) = 4 ; *((_DWORD *)this + 44 ) = 5 ; *((_DWORD *)this + 46 ) = 5 ; *((_DWORD *)this + 47 ) = 6 ; *((_DWORD *)this + 53 ) = 5 ; *((_DWORD *)this + 56 ) = 7 ; *((_DWORD *)this + 65 ) = 10 ; *((_DWORD *)this + 66 ) = 10 ; *((_DWORD *)this + 67 ) = 7 ; *((_DWORD *)this + 68 ) = 8 ; *((_DWORD *)this + 70 ) = 4 ; *((_DWORD *)this + 71 ) = 11 ; *((_DWORD *)this + 72 ) = 9 ; *((_DWORD *)this + 77 ) = 11 ; *((_DWORD *)this + 81 ) = 10 ; *((_DWORD *)this + 90 ) = 6 ; *((_DWORD *)this + 91 ) = 12 ; *((_DWORD *)this + 92 ) = 11 ; *((_DWORD *)this + 94 ) = 12 ; *((_DWORD *)this + 101 ) = 11 ; *((_DWORD *)this + 103 ) = 13 ; *((_DWORD *)this + 112 ) = 16 ; *((_DWORD *)this + 113 ) = 14 ; *((_DWORD *)this + 122 ) = 15 ; *((_DWORD *)this + 131 ) = 16 ; *((_DWORD *)this + 140 ) = 17 ; *((_DWORD *)this + 142 ) = 19 ; *((_DWORD *)this + 143 ) = 19 ; *((_DWORD *)this + 144 ) = 18 ; *((_DWORD *)this + 149 ) = 13 ; *((_DWORD *)this + 153 ) = 21 ; *((_DWORD *)this + 154 ) = 21 ; *((_DWORD *)this + 155 ) = 19 ; *((_DWORD *)this + 164 ) = 20 ; *((_DWORD *)this + 166 ) = 21 ; *((_DWORD *)this + 173 ) = 22 ; *((_DWORD *)this + 175 ) = 21 ; *((_DWORD *)this + 176 ) = 21 ; *((_DWORD *)this + 177 ) = 17 ; *((_DWORD *)this + 178 ) = 21 ; *((_DWORD *)this + 179 ) = 22 ; *((_DWORD *)this + 188 ) = 23 ; *((_DWORD *)this + 190 ) = 25 ; *((_DWORD *)this + 191 ) = 24 ; *((_DWORD *)this + 197 ) = 25 ; *((_DWORD *)this + 200 ) = 25 ; *((_DWORD *)this + 209 ) = 26 ; *((_DWORD *)this + 218 ) = 28 ; *((_DWORD *)this + 219 ) = 27 ; *((_DWORD *)this + 228 ) = 28 ; *((_DWORD *)this + 230 ) = 29 ; *((_DWORD *)this + 237 ) = 28 ; *((_DWORD *)this + 239 ) = 30 ; *((_DWORD *)this + 248 ) = 26 ; *((_DWORD *)this + 249 ) = 30 ; *((_DWORD *)this + 250 ) = 26 ; *((_DWORD *)this + 251 ) = 31 ; *((_DWORD *)this + 260 ) = 32 ; *((_DWORD *)this + 262 ) = 33 ; *((_DWORD *)this + 269 ) = 32 ; *((_DWORD *)this + 271 ) = 35 ; *((_DWORD *)this + 272 ) = 34 ; *((_DWORD *)this + 281 ) = 36 ; *((_DWORD *)this + 282 ) = 37 ; *((_DWORD *)this + 283 ) = 35 ; *((_DWORD *)this + 292 ) = 36 ; *((_DWORD *)this + 294 ) = 37 ; *((_DWORD *)this + 301 ) = 36 ; *((_DWORD *)this + 303 ) = 38 ; *((_DWORD *)this + 312 ) = 39 ; *((_DWORD *)this + 321 ) = 40 ; *((_DWORD *)this + 330 ) = 41 ; *((_DWORD *)this + 339 ) = 41 ; *((_DWORD *)this + 340 ) = 42 ; *((_DWORD *)this + 342 ) = 43 ; *((_DWORD *)this + 349 ) = 45 ; *((_DWORD *)this + 351 ) = 45 ; *((_DWORD *)this + 352 ) = 43 ; *((_DWORD *)this + 353 ) = 46 ; *((_DWORD *)this + 354 ) = 43 ; *((_DWORD *)this + 355 ) = 44 ; *((_DWORD *)this + 364 ) = 45 ; *((_DWORD *)this + 366 ) = 47 ; *((_DWORD *)this + 367 ) = 41 ; *((_DWORD *)this + 368 ) = 46 ; *((_DWORD *)this + 373 ) = 41 ; *((_DWORD *)this + 377 ) = 47 ; *((_DWORD *)this + 386 ) = 49 ; *((_DWORD *)this + 387 ) = 48 ; *((_DWORD *)this + 396 ) = 49 ; *((_DWORD *)this + 398 ) = 50 ; *((_DWORD *)this + 405 ) = 52 ; *((_DWORD *)this + 407 ) = 51 ; *((_DWORD *)this + 416 ) = 52 ; *((_DWORD *)this + 425 ) = 53 ; *((_DWORD *)this + 434 ) = 55 ; *((_DWORD *)this + 435 ) = 54 ; *((_DWORD *)this + 444 ) = 55 ; *((_DWORD *)this + 446 ) = 58 ; *((_DWORD *)this + 447 ) = 56 ; *((_DWORD *)this + 453 ) = 57 ; *((_DWORD *)this + 456 ) = 57 ; *((_DWORD *)this + 465 ) = 58 ; *((_DWORD *)this + 474 ) = 60 ; *((_DWORD *)this + 475 ) = 59 ; *((_DWORD *)this + 484 ) = 60 ; *((_DWORD *)this + 486 ) = 61 ; *((_DWORD *)this + 493 ) = 60 ; *((_DWORD *)this + 495 ) = 62 ; *((_DWORD *)this + 504 ) = 63 ; *((_DWORD *)this + 513 ) = 66 ; *((_DWORD *)this + 514 ) = 66 ; *((_DWORD *)this + 515 ) = 64 ; *((_DWORD *)this + 524 ) = 65 ; *((_DWORD *)this + 526 ) = 66 ; *((_DWORD *)this + 533 ) = 68 ; *((_DWORD *)this + 535 ) = 67 ; *((_DWORD *)this + 544 ) = 68 ; *((_DWORD *)this + 553 ) = 69 ; *((_DWORD *)this + 562 ) = 70 ; *((_DWORD *)this + 571 ) = 66 ; *((_DWORD *)this + 572 ) = 71 ; *((_DWORD *)this + 574 ) = 73 ; *((_DWORD *)this + 575 ) = 74 ; *((_DWORD *)this + 576 ) = 72 ; *((_DWORD *)this + 581 ) = 67 ; *((_DWORD *)this + 585 ) = 74 ; *((_DWORD *)this + 586 ) = 73 ; *((_DWORD *)this + 595 ) = 74 ; *((_DWORD *)this + 604 ) = 75 ; *((_DWORD *)this + 606 ) = 76 ; *((_DWORD *)this + 613 ) = 75 ; *((_DWORD *)this + 615 ) = 77 ; *((_DWORD *)this + 624 ) = 78 ; *((_DWORD *)this + 633 ) = 79 ; *((_DWORD *)this + 642 ) = 82 ; *((_DWORD *)this + 643 ) = 80 ; *((_DWORD *)this + 652 ) = 81 ; *((_DWORD *)this + 654 ) = 82 ; *((_DWORD *)this + 661 ) = 81 ; *((_DWORD *)this + 663 ) = 83 ; *((_DWORD *)this + 672 ) = 84 ; *((_DWORD *)this + 681 ) = 85 ; *((_DWORD *)this + 690 ) = 86 ; *((_DWORD *)this + 699 ) = 88 ; *((_DWORD *)this + 700 ) = 87 ; *((_DWORD *)this + 702 ) = 89 ; *((_DWORD *)this + 703 ) = 87 ; *((_DWORD *)this + 704 ) = 88 ; *((_DWORD *)this + 709 ) = 83 ; *((_DWORD *)this + 713 ) = 91 ; *((_DWORD *)this + 714 ) = 89 ; *((_DWORD *)this + 723 ) = 90 ; *((_DWORD *)this + 732 ) = 91 ; *((_DWORD *)this + 734 ) = 94 ; *((_DWORD *)this + 735 ) = 87 ; *((_DWORD *)this + 736 ) = 87 ; *((_DWORD *)this + 737 ) = 92 ; *((_DWORD *)this + 741 ) = 93 ; *((_DWORD *)this + 746 ) = 88 ; *((_DWORD *)this + 747 ) = 93 ; *((_DWORD *)this + 756 ) = 94 ; *((_DWORD *)this + 758 ) = 95 ; *((_DWORD *)this + 765 ) = 97 ; *((_DWORD *)this + 767 ) = 97 ; *((_DWORD *)this + 768 ) = 96 ; *((_DWORD *)this + 777 ) = 99 ; *((_DWORD *)this + 778 ) = 99 ; *((_DWORD *)this + 779 ) = 97 ; *((_DWORD *)this + 788 ) = 98 ; *((_DWORD *)this + 790 ) = 99 ; *((_DWORD *)this + 797 ) = 100 ; *((_DWORD *)this + 799 ) = 100 ; *((_DWORD *)this + 808 ) = 101 ; *((_DWORD *)this + 817 ) = 102 ; *((_DWORD *)this + 826 ) = 103 ; *((_DWORD *)this + 835 ) = 99 ; *((_DWORD *)this + 836 ) = 104 ; *((_DWORD *)this + 838 ) = 106 ; *((_DWORD *)this + 839 ) = 105 ; *((_DWORD *)this + 845 ) = 100 ; *((_DWORD *)this + 848 ) = 108 ; *((_DWORD *)this + 849 ) = 108 ; *((_DWORD *)this + 850 ) = 101 ; *((_DWORD *)this + 851 ) = 106 ; *((_DWORD *)this + 860 ) = 107 ; *((_DWORD *)this + 862 ) = 108 ; *((_DWORD *)this + 869 ) = 107 ; *((_DWORD *)this + 871 ) = 109 ; *((_DWORD *)this + 880 ) = 109 ; *((_DWORD *)this + 881 ) = 109 ; *((_DWORD *)this + 882 ) = 110 ; *((_DWORD *)this + 891 ) = 111 ; *((_DWORD *)this + 894 ) = 107 ; *((_DWORD *)this + 895 ) = 111 ; *((_DWORD *)this + 896 ) = 112 ; *((_DWORD *)this + 900 ) = 114 ; *((_DWORD *)this + 901 ) = 114 ; *((_DWORD *)this + 905 ) = 108 ; *((_DWORD *)this + 906 ) = 113 ; *((_DWORD *)this + 915 ) = 114 ; *((_DWORD *)this + 918 ) = 116 ; *((_DWORD *)this + 919 ) = 114 ; *((_DWORD *)this + 920 ) = 115 ; *((_DWORD *)this + 924 ) = 110 ; *((_DWORD *)this + 925 ) = 110 ; *((_DWORD *)this + 929 ) = 115 ; *((_DWORD *)this + 930 ) = 116 ; *((_DWORD *)this + 939 ) = 117 ; *((_DWORD *)this + 948 ) = 118 ; *((_DWORD *)this + 950 ) = 119 ; *((_DWORD *)this + 957 ) = 120 ; *((_DWORD *)this + 959 ) = 120 ; *((_DWORD *)this + 968 ) = 121 ; *((_DWORD *)this + 977 ) = 122 ; *((_DWORD *)this + 986 ) = 123 ; *((_DWORD *)this + 995 ) = 125 ; *((_DWORD *)this + 996 ) = 124 ; *((_DWORD *)this + 998 ) = 125 ; *((_DWORD *)this + 1005 ) = 124 ; *((_DWORD *)this + 1007 ) = 126 ; *((_DWORD *)this + 1016 ) = 127 ; *((_DWORD *)this + 1025 ) = 128 ; *((_DWORD *)this + 1034 ) = 130 ; *((_DWORD *)this + 1035 ) = 129 ; *((_DWORD *)this + 1044 ) = 130 ; *((_DWORD *)this + 1046 ) = 133 ; *((_DWORD *)this + 1047 ) = 131 ; *((_DWORD *)this + 1053 ) = 126 ; *((_DWORD *)this + 1056 ) = 132 ; *((_DWORD *)this + 1065 ) = 128 ; *((_DWORD *)this + 1066 ) = 132 ; *((_DWORD *)this + 1067 ) = 133 ; *((_DWORD *)this + 1076 ) = 134 ; *((_DWORD *)this + 1078 ) = 135 ; *((_DWORD *)this + 1085 ) = 136 ; *((_DWORD *)this + 1087 ) = 136 ; *((_DWORD *)this + 1096 ) = 137 ; *((_DWORD *)this + 1105 ) = 138 ; *((_DWORD *)this + 1114 ) = 139 ; *((_DWORD *)this + 1123 ) = 142 ; *((_DWORD *)this + 1124 ) = 140 ; *((_DWORD *)this + 1126 ) = 142 ; *((_DWORD *)this + 1127 ) = 143 ; *((_DWORD *)this + 1128 ) = 141 ; *((_DWORD *)this + 1133 ) = 140 ; *((_DWORD *)this + 1137 ) = 144 ; *((_DWORD *)this + 1138 ) = 142 ; *((_DWORD *)this + 1147 ) = 143 ; *((_DWORD *)this + 1156 ) = 144 ; *((_DWORD *)this + 1158 ) = 147 ; *((_DWORD *)this + 1159 ) = 144 ; *((_DWORD *)this + 1160 ) = 146 ; *((_DWORD *)this + 1161 ) = 145 ; *((_DWORD *)this + 1165 ) = 146 ; *((_DWORD *)this + 1170 ) = 141 ; *((_DWORD *)this + 1171 ) = 146 ; *((_DWORD *)this + 1180 ) = 147 ; *((_DWORD *)this + 1182 ) = 148 ; *((_DWORD *)this + 1189 ) = 147 ; *((_DWORD *)this + 1191 ) = 148 ; *((_DWORD *)this + 1192 ) = 149 ; *((_DWORD *)this + 1201 ) = 151 ; *((_DWORD *)this + 1202 ) = 151 ; *((_DWORD *)this + 1203 ) = 150 ; *((_DWORD *)this + 1212 ) = 151 ; *((_DWORD *)this + 1214 ) = 152 ; *((_DWORD *)this + 1221 ) = 154 ; *((_DWORD *)this + 1223 ) = 153 ; *((_DWORD *)this + 1232 ) = 154 ; *((_DWORD *)this + 1241 ) = 155 ; *((_DWORD *)this + 1250 ) = 156 ; *((_DWORD *)this + 1259 ) = 156 ; *((_DWORD *)this + 1260 ) = 157 ; *((_DWORD *)this + 1262 ) = 157 ; *((_DWORD *)this + 1263 ) = 158 ; *((_DWORD *)this + 1269 ) = 160 ; *((_DWORD *)this + 1272 ) = 159 ; *((_DWORD *)this + 1281 ) = 159 ; *((_DWORD *)this + 1282 ) = 155 ; *((_DWORD *)this + 1283 ) = 160 ; *((_DWORD *)this + 1292 ) = 161 ; *((_DWORD *)this + 1294 ) = 164 ; *((_DWORD *)this + 1295 ) = 164 ; *((_DWORD *)this + 1296 ) = 162 ; *((_DWORD *)this + 1301 ) = 161 ; *((_DWORD *)this + 1305 ) = 163 ; *((_DWORD *)this + 1314 ) = 159 ; *((_DWORD *)this + 1315 ) = 164 ; *((_DWORD *)this + 1324 ) = 165 ; *((_DWORD *)this + 1326 ) = 167 ; *((_DWORD *)this + 1327 ) = 161 ; *((_DWORD *)this + 1328 ) = 166 ; *((_DWORD *)this + 1333 ) = 168 ; *((_DWORD *)this + 1337 ) = 169 ; *((_DWORD *)this + 1338 ) = 167 ; *((_DWORD *)this + 1347 ) = 168 ; *((_DWORD *)this + 1350 ) = 169 ; *((_DWORD *)this + 1356 ) = 171 ; *((_DWORD *)this + 1357 ) = 170 ; *((_DWORD *)this + 1359 ) = 170 ; *((_DWORD *)this + 1368 ) = 171 ; *((_DWORD *)this + 1377 ) = 167 ; *((_DWORD *)this + 1378 ) = 173 ; *((_DWORD *)this + 1379 ) = 172 ; *((_DWORD *)this + 1388 ) = 173 ; *((_DWORD *)this + 1390 ) = 174 ; *((_DWORD *)this + 1397 ) = 169 ; *((_DWORD *)this + 1399 ) = 170 ; *((_DWORD *)this + 1400 ) = 174 ; *((_DWORD *)this + 1401 ) = 177 ; *((_DWORD *)this + 1402 ) = 177 ; *((_DWORD *)this + 1403 ) = 175 ; *((_DWORD *)this + 1406 ) = 176 ; *((_DWORD *)this + 1412 ) = 175 ; *((_DWORD *)this + 1413 ) = 177 ; *((_DWORD *)this + 1415 ) = 176 ; *((_DWORD *)this + 1416 ) = 177 ; *((_DWORD *)this + 1425 ) = 178 ; *((_DWORD *)this + 1434 ) = 179 ; *((_DWORD *)this + 1443 ) = 180 ; *((_DWORD *)this + 1452 ) = 181 ; *((_DWORD *)this + 1461 ) = 184 ; *((_DWORD *)this + 1478 ) = 0 ; *((_DWORD *)this + 1479 ) = 23 ; *((_DWORD *)this + 1480 ) = 21 ; *((_DWORD *)this + 1481 ) = 32 ; *((_DWORD *)this + 1482 ) = 19 ; *((_DWORD *)this + 1483 ) = 17 ; *((_DWORD *)this + 1484 ) = 31 ; *((_DWORD *)this + 1485 ) = 38 ; *((_DWORD *)this + 1486 ) = 0 ; *(_QWORD *)((char *)this + 5948 ) = 0 ; *(_QWORD *)((char *)this + 5956 ) = 0 ; *(_QWORD *)((char *)this + 5964 ) = 0 ; *(_QWORD *)((char *)this + 5972 ) = 0 ; }
通过观察状态机的逻辑,我们发现这是一个 Flag 校验机。这意味着正确的输入会让状态机按部就班地晋级:State 0→State 1→State 2⋯→State 181 因此这是一条单向链表
所以给出 exp:
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 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 import re code_raw = "" " std::vector<Step>::vector(this, a2); v2 = (_DWORD *)((char *)this + 24); memset(v2, 0, 0x1700u); "" "def solve_linear_chain(): print ("[*] Parsing code..." ) graph = {} pattern = re.compile(r'\+\s*(\d +)\)\s*=\s*(\d +);') matches = pattern.findall(code_raw) for offset_str, value_str in matches: offset = int(offset_str) value = int(value_str) if offset >= 1478: continue rel_offset = offset - 6 if rel_offset < 0: continue state = rel_offset hit = rel_offset % 8 if state not in graph : graph [state] = {} graph [state][hit] = value if 0 not in graph : graph [0] = {} graph [0][0] = 1 print (f"[*] Graph parsed with {len(graph)} source states." ) print ("[*] Tracing the linear chain (0 -> 1 -> ... -> 181)..." ) path = [] for current_state in range (181): found_hit = -1 if current_state in graph : for hit, next_state in graph [current_state].items(): if next_state == current_state + 1: found_hit = hit break if found_hit != -1: path.append (found_hit) else : print (f"[-] Broken chain at State {current_state}! Could not find transition to {current_state + 1}" ) break print (f"[*] Chain complete. Length: {len(path)}" ) flag = "" val = 0 last_hit = -1 for hit in path: if hit <= last_hit: flag += chr(val) val = 0 last_hit = -1 val |= (1 << hit) last_hit = hit flag += chr(val) print ("\n" + "=" * 40) print (f"FLAG: {flag}" ) print ("=" * 40) if __name__ == "__main__" : solve_linear_chain()