本帖最后由 skywilling 于 2017-7-20 20:02 编辑
0x00前言
今天很高兴为大家带来第十届全国大学生信息安全大赛之逆向--apk题目的writeup。到目前为止,我还没看过官方的writeup或者其他人的writeup,所以不保证本文章的解题思路是最简单易懂,当然,我会尽量讲解的详细一点。需要注意的是,本文章需要读者熟悉smali语言。下面正式开始讲解。
0x01运行
一般像这种比赛的apk题目是不会加壳的,所以,直接跳过查壳的步骤,运行apk。
标准模式的Android题目,一个输入框,一个按钮以及一个输出框,输出的数据也十分简单。
0x02反编译
看了apk的运行效果之后,直接放入jadx中进行反编译(相比于其他的反编译软件,我更喜欢jadx)。
首先,我们需要找到入口Activity,在AndroidManifest.xml中我们可以很清楚的看到入口Activity为com.example.ichunqiu2.P_ichunqiu
接下来直接打开对应的类P_ichunqiu,可以看到反编译后的Java代码:
[Java] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | public class P_ichunqiu extends Activity {
public static String A = "" ;
public static String B = "" ;
private Class<?> clazz;
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_p_ichunqiu);
((Button) findViewById(R.id.button1)).setOnClickListener( new OnClickListener() {
public void onClick(View v) {
TextView show = (TextView) P_ichunqiu. this .findViewById(R.id.textView1);
String words = ((EditText) P_ichunqiu. this .findViewById(R.id.editText1)).getText().toString();
wick.show(words);
if ( new simple(words).check()) {
show.setText(P_ichunqiu.A);
} else {
show.setText(P_ichunqiu.B);
}
}
});
}
|
这段Java代码的逻辑很清晰,变量words中保存着要输入的数据,然后传入wick类的show方法中,接下来就是一个条件判断语句,条件成立要求simple类中的check方法返回值为true。下面依次查看wick类和simple类:
wick类:
[Java] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 | public class wick {
public static native boolean a();
static {
System.loadLibrary( "P_jni" );
}
public static String show(String A) {
return a() ? A : A;
}
}
|
show方法就是直接返回了传入的字符串,并没有对字符串做什么处理,如果要深究的话,show方法中调用native层中的方法a为P_ichunqiu.A和P_ichunqiu.B赋值,也就是要输出的数据。
simple类:
[Java] 纯文本查看 复制代码 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 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 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 | package com.example.ichunqiu2;
public class simple {
private byte [] A = new byte [ 50 ];
private byte [] B;
public simple(String a) {
this .B = a.getBytes();
for ( int i = 0 ; i < this .B.length; i++) {
this .A = this .B;
}
this .B = new byte [ 50 ];
}
public boolean check() {
throw new UnsupportedOperationException( "Method not decompiled: com.example.ichunqiu2.simple.check():boolean" );
}
}
|
看到这里,我们可以发现,这道题目的重点就是这个不能正确反编译为Java代码的check方法。
这道题目一个难点就是还原check方法的Java代码,下面就开始还原Java代码。
0x03还原Java代码
我们直接在IDA中打开apk的classes.dex文件,定位到simple类的check方法
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | CODE:000009C4 # Source file: simple.java
CODE:000009C4 public boolean com.example.ichunqiu2.simple.check()
CODE:000009C4 this = v14 # CODE XREF: P_ichunqiu $ 1_onClick@VL+4Cj
CODE:000009C4 const/16 v13, 0x4D
CODE:000009C8 const/16 v12, 0x31
CODE:000009CC const/16 v11, 0x39
CODE:000009D0 const/16 v10, 0x32
CODE:000009D4 const/16 v9, 0x30
CODE:000009D8 .prologue_end
CODE:000009D8 .line 17
CODE:000009D8 const/16 v7, 0xCB
CODE:000009DC new-array v2, v7, <t: byte []> # 长度为v7的数组v2
CODE:000009E0 const/4 v7, 0
CODE:000009E2 .line 18
CODE:000009E2 const/16 v8, 0x2F
CODE:000009E6 aput- byte v8, v2, v7 # v2[0]=0x2F
CODE:000009EA const/4 v7, 1
CODE:000009EC aput- byte v9, v2, v7 # v2[1]=0x30
CODE:000009F0 const/4 v7, 2
CODE:000009F2 const/16 v8, 0x51
CODE:000009F6 aput- byte v8, v2, v7 # v2[2]=0x51
CODE:000009FA const/4 v7, 3
CODE:000009FC const/16 v8, 0x52
|
大体看一下smali代码,可以大致的分为两部分,第一部分是为数组v2赋值,第二部分是执行switch语句。
第一部分:
(1)可以直接复制jadx反编译出来的这一段Java代码
(2)也可以进行动态调试,直接将数组复制出来
最后我们得到的数组内容如下:
[Java] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 | { '/' , '0' , 'Q' , 'R' , 'O' , '6' , 'M' , '0' , '2' , '0' , '0' , '/' , '0' , 'A' , '6' , 'M' ,
'0' , '2' , '0' , '0' , '/' , '9' , '9' , 'F' , '0' , '/' , '1' , '0' , '8' , 'F' , '1' , '/' ,
'1' , '1' , '1' , 'F' , '2' , '/' , '5' , '3' , 'F' , '3' , '/' , '1' , '0' , '1' , 'F' , '4' ,
'/' , '1' , '1' , '4' , 'F' , '5' , '/' , '0' , 'F' , '6' , 'O' , '0' , 'G' , '0' , 'M' , '0' ,
'0' , '2' , '0' , '0' , 'A' , '0' , 'D' , '0' , 'M' , '0' , '0' , '2' , '0' , '0' , 'O' , '1' ,
'G' , '1' , 'M' , '0' , '0' , '2' , '0' , '0' , 'A' , '1' , 'D' , '1' , 'M' , '0' , '0' , '2' ,
'0' , '0' , 'O' , '2' , 'G' , '2' , 'M' , '0' , '0' , '2' , '0' , '0' , 'A' , '2' , 'D' , '2' ,
'M' , '0' , '0' , '2' , '0' , '0' , 'O' , '3' , 'G' , '3' , 'M' , '0' , '0' , '2' , '0' , '0' ,
'A' , '3' , 'D' , '3' , 'M' , '0' , '0' , '2' , '0' , '0' , 'O' , '4' , 'G' , '4' , 'M' , '0' ,
'0' , '2' , '0' , '0' , 'A' , '4' , 'D' , '4' , 'M' , '0' , '0' , '2' , '0' , '0' , 'O' , '5' ,
'G' , '5' , 'M' , '0' , '0' , '2' , '0' , '0' , 'A' , '5' , 'D' , '5' , 'M' , '0' , '0' , '2' ,
'0' , '0' , '/' , '1' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' ,
'\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '/' , '0' , '\0' }
|
这个数组很有意思呢。
第二部分:
其实这道题目作者就是利用了现在大部分反编译工具不能完整反编译大量switch分支语句的缺点,来给解题者制造障碍的。(如果有谁知道可以完美反编译大量switch分支语句的,欢迎分享)
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | CODE:0000107C . local name : 'code' type : '[B'
CODE:0000107C code = v2
CODE:0000107C .line 34
CODE:0000107C const/4 v3, 0
CODE:0000107E . local name : 'cur' type : 'I'
CODE:0000107E cur = v3
CODE:0000107E .line 35
CODE:0000107E const/4 v0, 0
CODE:00001080 . local name : 'a' type : 'B'
CODE:00001080 a = v0
CODE:00001080 const/4 v1, 0
CODE:00001082 . local name : 'b' type : 'B'
CODE:00001082 b = v1
CODE:00001082 .line 36
CODE:00001082 const/16 v7, 0x3E8
CODE:00001086 new-array v5, v7, <t: byte []>
CODE:0000108A . local name : 'stack' type : '[B'
CODE:0000108A stack = v5
CODE:0000108A .line 37
CODE:0000108A const/4 v4, 0
CODE:0000108C . local name : 'depth' type : 'I'
CODE:0000108C depth = v4
CODE:0000108C .line 38
CODE:0000108C const/4 v6, 0
CODE:0000108E
|
像这些局部变量,大部分反编译工具是识别不出来的,其实在某种程度上,降低手工还原Java代码的难度,因为这些局部变量命名都有特定的意义,像stack(堆),depth(深度),这两者很容易就联系到了一起。
接下来就是switch分支语句了,要还原出Java代码需要花费一些时间了。
下面是我还原出来的代码:
[Java] 纯文本查看 复制代码 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 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 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | public int check() {
int [] r2 = { '/' , '0' , 'Q' , 'R' , 'O' , '6' , 'M' , '0' , '2' , '0' , '0' , '/' , '0' , 'A' ,
'6' , 'M' , '0' , '2' , '0' , '0' , '/' , '9' , '9' , 'F' , '0' , '/' , '1' , '0' , '8' , 'F' , '1' , '/' ,
'1' , '1' , '1' , 'F' , '2' , '/' , '5' , '3' , 'F' , '3' , '/' , '1' , '0' , '1' , 'F' , '4' ,
'/' , '1' , '1' , '4' , 'F' , '5' , '/' , '0' , 'F' , '6' , 'O' , '0' , 'G' , '0' , 'M' , '0' ,
'0' , '2' , '0' , '0' , 'A' , '0' , 'D' , '0' , 'M' , '0' , '0' , '2' , '0' , '0' , 'O' , '1' ,
'G' , '1' , 'M' , '0' , '0' , '2' , '0' , '0' , 'A' , '1' , 'D' , '1' , 'M' , '0' , '0' , '2' ,
'0' , '0' , 'O' , '2' , 'G' , '2' , 'M' , '0' , '0' , '2' , '0' , '0' , 'A' , '2' , 'D' , '2' ,
'M' , '0' , '0' , '2' , '0' , '0' , 'O' , '3' , 'G' , '3' , 'M' , '0' , '0' , '2' , '0' , '0' ,
'A' , '3' , 'D' , '3' , 'M' , '0' , '0' , '2' , '0' , '0' , 'O' , '4' , 'G' , '4' , 'M' , '0' ,
'0' , '2' , '0' , '0' , 'A' , '4' , 'D' , '4' , 'M' , '0' , '0' , '2' , '0' , '0' , 'O' , '5' ,
'G' , '5' , 'M' , '0' , '0' , '2' , '0' , '0' , 'A' , '5' , 'D' , '5' , 'M' , '0' , '0' , '2' ,
'0' , '0' , '/' , '1' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' ,
'\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '\0' , '/' , '0' , '\0' };
int code[]=r2;
int cur= 0 ;
int a= 0 ,b= 0 ;
int stack[]= new int [ 0x3E8 ];
int depth= 0 ;
int temp= 0 ;
int v7;
int v13 = 77 ;
int v12 = 49 ;
int v11 = 57 ;
int v10 = 50 ;
int v9 = 48 ;
while ( true ){
v7=code[cur];
System.out.printf( "v7=%d--cur=%d--code[cur]=%c--a=%d--b=%c\n" ,v7,cur,code[cur],a,b);
switch (v7){
default :
cur++;
break ;
case 81 :
stack[depth]=a;
depth++;
cur++;
break ;
case 82 :
depth--;
b=stack[depth];
cur++;
break ;
case 87 :
depth--;
a=stack[depth];
cur++;
break ;
case 69 :
stack[depth]=b;
depth++;
cur++;
break ;
case 84 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
a=stack[temp];
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
a=stack[temp];
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 89 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
stack[temp]=a;
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
stack[temp]=a;
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 73 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
stack[temp]=b;
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
stack[temp]=b;
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 85 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
b=stack[temp];
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
b=stack[temp];
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 79 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
a=A[temp];
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
a=A[temp];
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 80 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
A[temp]=( byte ) a;
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
A[temp]=( byte ) a;
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 65 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
b=A[temp];
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
b=A[temp];
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 83 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
A[temp]=( byte ) b;
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
A[temp]=( byte ) b;
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 68 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
a=B[temp];
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
a=B[temp];
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 70 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
B[temp]=( byte ) a;
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
B[temp]=( byte ) a;
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 71 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
b=B[temp];
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
b=B[temp];
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 72 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
B[temp]=( byte ) b;
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
B[temp]=( byte ) b;
temp= 0 ;
cur++;
break ;
}
}
}
break ;
case 74 :
v7=a^b;
a=v7;
cur++;
break ;
case 75 :
v7=a|b;
a=v7;
cur++;
break ;
case 76 :
v7=a&b;
a=v7;
cur++;
break ;
case 90 :
v7=a^(- 1 );
a=v7;
break ;
case 88 :
v7=a+b;
a=v7;
break ;
case 67 :
v7=a-b;
a=v7;
break ;
case 86 :
v7=a*b;
a=v7;
break ;
case 66 :
v7=a/b;
a=v7;
break ;
case 78 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
cur=temp;
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
cur=temp;
temp= 0 ;
break ;
}
}
}
break ;
case 77 :
if (a>=b){
cur++;
break ;
} else {
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
cur=temp;
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
cur=temp;
temp= 0 ;
break ;
}
}
}
}
break ;
case 47 :
while ( true ){
cur++;
temp*= 0xA ;
v7=code[cur];
v7+=temp;
temp=v7- 0x30 ;
v7=cur+ 1 ;
v7=code[v7];
if (v7>v11){
a=temp;
temp= 0 ;
cur++;
break ;
} else {
v7=cur+ 1 ;
v7=code[v7];
if (v7<v9){
a=temp;
temp= 0 ;
break ;
}
}
}
break ;
case 0 :
if (a== 0 ){
v7= 0 ;
} else {
v7= 1 ;
}
return v7;
}
}
}
|
就算还原出来代码,要理解代码要实现的功能也是相当困难的,这就是第二大难点了。
所以我们就需要仔细分析代码运行过程中一些变量了。
0x04分析代码运行过程
首先我是输入不同的内容,然后分析switch分支语句的执行情况。
不同的输入,却执行相同的流程
这个问题困扰了我一些时间,不过静下心来仔细想一想,可能输入的数据需要满足某种条件吧。
接下来,我们按照switch分支语句执行的顺序来分析一下,到底进行了怎样的运算过程。
下面是我分析的结果
我们发现程序对数组A(存放了我们输入的数据)中下标为6的地方访问了两次,这就值得分析一下了。
我输入的数据长度都是大于6的,所以A[6]一定不为0,接下来,我测试了长度大于6的大量数据,发现执行流程都是一样的。
所以真相只有一个,输入数据的长度要求小于等于6(A[6]一定为0)。
下面是我对一个长度小于6数据的测试结果:
[Asm] 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 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 | v7=47--cur=0--code[cur]=/
v7=81--cur=2--code[cur]=Q
v7=82--cur=3--code[cur]=R
v7=79--cur=4--code[cur]=O
v7=77--cur=6--code[cur]=M
v7=48--cur=7--code[cur]=0
v7=50--cur=8--code[cur]=2
v7=48--cur=9--code[cur]=0
v7=48--cur=10--code[cur]=0
v7=47--cur=11--code[cur]=/
v7=65--cur=13--code[cur]=A
v7=77--cur=15--code[cur]=M
v7=48--cur=16--code[cur]=0
v7=50--cur=17--code[cur]=2
v7=48--cur=18--code[cur]=0
v7=48--cur=19--code[cur]=0
v7=47--cur=20--code[cur]=/ a=99
v7=70--cur=23--code[cur]=F B[0]=a
v7=47--cur=25--code[cur]=/ a=108
v7=70--cur=29--code[cur]=F B[1]=a
v7=47--cur=31--code[cur]=/ a=111
v7=70--cur=35--code[cur]=F B[2]=a
v7=47--cur=37--code[cur]=/ a=53
v7=70--cur=40--code[cur]=F B[3]=a
v7=47--cur=42--code[cur]=/ a=101
v7=70--cur=46--code[cur]=F B[4]=a
v7=47--cur=48--code[cur]=/ a=114
v7=70--cur=52--code[cur]=F B[5]=a
v7=47--cur=54--code[cur]=/ a=0
v7=70--cur=56--code[cur]=F B[6]=a
v7=79--cur=58--code[cur]=O a=A[0]
v7=71--cur=60--code[cur]=G b=B[0]
v7=77--cur=62--code[cur]=M if a>=b
v7=48--cur=201--code[cur]=0
v7=0--cur=202--code[cur]=
|
前半段与之前的一样,后半段才是重点,通过我对switch分支语句的分析,我得到了后半段的代码执行过程。
首先是向数组B中填充了6个数据,然后分别从数组A,B中得到下标相同的数据,然后进行比较。
那么,答案很可能就是数组B里面的数据了,{99,108,111,53,101,114,0}(10进制)。
如上图,我们得到数组B里面的数据,先放到代码里面运行一下,
重点是要看最后一行变量a的值,a=1,所以返回的值就是true了。
到这里,就已经解出了答案。
0x05后记
总体来看,这道题目还算简单,毕竟没有涉及到加密算法。题目中的code数组说白了就是指令集和数据集的集合。
老规矩,题目和代码会在附件中给出。
成功截图:
附件: http://pan.baidu.com/s/1gf1QO0b 密码: 72bc
版权声明:允许转载,但是一定要注明出处。 |