【Android】【攻防世界】easy-app 一开始想用ida进行动调,但是失败了
丢进jadx发现其主要flag检查逻辑都在native层中
于是就直接去native层查看,有点繁杂,先从check开始查看:最后进行了一次base64
base64是魔改base64,换表+密文换位,加入正常的base密文是0123,这个密文就是2013
所以解base64的时候需要进行换位置然后解正常的base64
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 import  base64import  structENCODED_STR = "e)n*pNe%PQy!^oS(@HtkUu+Cd$#hmmK&ieytiWwYkIA="  TEA_KEY = [0x42 , 0x37 , 0x2c , 0x21 ]   DELTA = 0x9E3779B9  k = struct.unpack("<4I" , bytes (TEA_KEY * 4 )) def  tea_decrypt_block (v0, v1, k ):    total = DELTA * 32      for  _ in  range (32 ):         v1 = (v1 - (((v0 << 4 ) + k[2 ]) ^ (v0 + total) ^ ((v0 >> 5 ) + k[3 ])) & 0xFFFFFFFF )         v0 = (v0 - (((v1 << 4 ) + k[0 ]) ^ (v1 + total) ^ ((v1 >> 5 ) + k[1 ])) & 0xFFFFFFFF )         total = (total - DELTA) & 0xFFFFFFFF      return  v0, v1 custom_table = "abcdefghijklmnopqrstuvwxyz!@#$%^&*()ABCDEFGHIJKLMNOPQRSTUVWXYZ+/"  standard_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"  reordered_str = ""  for  i in  range (0 , len (ENCODED_STR), 4 ):    group = ENCODED_STR[i:i+4 ]     if  len (group) == 4 :                  reordered_str += group[2 ] + group[0 ] + group[1 ] + group[3 ]     else :         reordered_str += group translated_str = '' .join(standard_table[custom_table.index(char)] if  char in  custom_table else  char for  char in  reordered_str) if  len (translated_str) % 4  != 0 :    translated_str += '='  * (4  - len (translated_str) % 4 ) encrypted_data = base64.b64decode(translated_str) for  i in  range (0 , len (encrypted_data), 4 ):    dword = struct.unpack("<I" , encrypted_data[i:i+4 ])[0 ]     print (f"0x{dword:08X}  ," ,end='' ) print ('\n' )
再往上看发现有tea加密但是我们不知道密钥,静态的是一个假密钥
于是用frida进行动调,拿到真正的密钥
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 function hookTest999(){       Java.perform(function(){          var libc_base = Module.getBaseAddress("libnative-lib.so" )          var keys = libc_base.add(0x3A010 );          console.log("libc_base : " , libc_base);          console.log("keys_address : " ,  keys);                  var size = 0x30 ;         try {              var instructionBytes = Memory.readByteArray(keys,  size);             console.log("instructionBytes:\n" ,  instructionBytes);                                       if (typeof Instruction !== 'undefined') {                  var instructions = Instruction.parse(keys,  instructionBytes);                 console.log("Disassembly:" ,  instructions);             }  else {                  console.warn("Instruction parser not available" );             }          }  catch (e) {              console.error("Memory read failed:" ,  e);         }           var MainActivity = Java.use("com.example.myapplication.MainActivity" );          MainActivity.check.implementation = function(input) {                   readInstructions();                           var result = this.check(input);         console.log(`Native check("${input}" ) returned:  ${ result} `);         return result;     } ;          console.log("[*] check() hook installed. Ready for input..." );     } ) } 
进行tea解密:
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 #include  <stdio.h>  #include  <stdint.h>  void  Decrypt (unsigned  int * vq,unsigned  int * vp,unsigned  int * k) {       unsigned  int  n=32 ,sum,y=*vq,z=*vp;     unsigned  int  delta=0x9E3779B9 ;     sum = 0x9E3779B9  * 32 ;     while (n-->0 ){         z-=( ((y>>5 )+k[3 ]) ^ ((y<<4 )+k[2 ]) ^ (sum + y) );         y-=( ((z<<4 )+k[0 ]) ^ ((z>>5 )+k[1 ]) ^ (sum + z));         sum-=delta;     }     *vq=y;     *vp=z; } int  main () {     unsigned  int  v[8 ] = {0x10E14834  ,0x3D635EFC  ,0xA2F3D91A  ,0xFBCABA4D  ,0x37702685  ,0x20C3B847  ,0x58138160  ,0xAB90BC8E };     unsigned  int  k[4 ]={0x42 , 0x37 , 0x2c , 0x21 }; 	 for (int  j=0 ;j<=7 ;j+=2 ) 	 { 		Decrypt(&v[j],&v[j+1 ], k); 		printf ("%x %x\n" ,v[j],v[j+1 ]); 	 }     return  0 ; } #36346065  38673534  #65353537  62303531  #61333232  34363160  #63316239  35356761  
再往上分析发现有两个CheckM和check1,他们两个的作用是将输入的字符串每个byte的高位分离出来,然后把前16个数字和后16个数字进行交换,然后再和原来的低位进行组合(用动调可知,测试数据:flag{11111111BBBBBBBBSSSSSSSSdddddddd})
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 function test666(){  Java.perform(function() {      const moduleName = "libnative-lib.so" ;      const funcOffset = 0xff40 ;      let baseAddr = Module.getBaseAddress(moduleName);     if (!baseAddr || baseAddr.isNull()) {          console.log("Error: Module "  + moduleName + " not found or base address is null" );         return;     }      console.log("Base address: "  + baseAddr);     let hookAddr = baseAddr.add(funcOffset);     console.log("Hook address: "  + hookAddr);     Interceptor.attach(hookAddr,  {          onEnter:  function(args) {                       } ,          onLeave:  function(retval) {              try {                                   let v38Addr = this.context.rsp.add(0x58 );                 console.log("RSP: "  + this.context.rsp);                 console.log("v38Addr: "  + v38Addr);                 if (!v38Addr || v38Addr.isNull()) {                      console.log("Error: v38Addr is invalid or null" );                     return;                 }                                   let flag = v38Addr.readU8();                 console.log("Flag: "  + flag);                 let isSso = (flag & 1 ) === 0 ;                 let dataPtr,  dataLen;                                  if (isSso) {                                           dataLen = flag >> 1 ;                     dataPtr = v38Addr.add(1 );                     console.log("SSO mode - dataLen: "  + dataLen + ", dataPtr: "  + dataPtr);                 }  else {                                           dataLen = Process.arch === 'x64' ? v38Addr.add(8 ).readU64() :  v38Addr.add(8 ).readU32();                     dataPtr = v38Addr.add(16 ).readPointer();                     console.log("Heap mode - dataLen: "  + dataLen + ", dataPtr: "  + dataPtr);                 }                                   if (!dataPtr || dataPtr.isNull() || dataLen <= 0 ) {                      console.log("Error: Invalid dataPtr or dataLen" );                     return;                 }                                   let instructionBytes = Memory.readByteArray(dataPtr,  320 );                 console.log("new instructionBytes :\n" ,  instructionBytes);             }  catch (e) {                  console.log("Error in onLeave: "  + e);             }          }      } ); } );} 
所以还要把刚才tea解出的结果拼成一个长hex串这个混淆然后转换成字符
1 2 3 4 5 6 7 8 9 10 11 tea="6560343634356738373535653135306232323361603136343962316361673535"  tea1=tea[::2 ]  tea2=tea[1 ::2 ]   temp=tea1[16 :]+tea1[:16 ]    flag=""  for  i in  range (len (temp)):    flag+=temp[i]+tea2[i] print (bytes .fromhex(flag))