so汇编unidbg逆向笔记-白盒aes和md5篇

if函数中如果是0则代表false,是1等于为true

  if ( a5 ){
    result = CSecFunctProvider::InsertCBCPadding(param, a3, a4, a4);
 }

2.白盒aes-cbc模式特征:

首先进行
1.初始化CWAESCipher对象
2.表转换
3.明文和iv进行异或
3.进行填充
4.循环判断是否加密完成
5.块加密(列表)在块这里进行dfa攻击
6.前九轮循环,循环完break
7.开始第10轮,并把加密结果进行返回

//第一个函数  初始化CWAESCipher对象,表转换,把加密结果返回
 int __fastcall aes_encrypt1(CSecFunctProvider *param, unsigned __int8 *a2, unsigned int *a3)
{
  _DWORD v7[7];
  //初始化CWAESCipher对象
  CWAESCipher::CWAESCipher((CWAESCipher *)v7);
  v7[0] = &off_1ADC0;
  //表转换
  CWAESCipher_Auth::WBACRAES_SwitchTable((CWAESCipher_Auth *)v7, 1);
  //最后加密并返回
  return CWAESCipher::WBACRAES128_EncryptCBC((CWAESCipher *)v7, param, a2, a3, 1);
}

//第二个函数 进行填充,然后循环判断是否加密完成,完成后退出
//看函数名有cbc模式,需要有iv,如果是ecb模式则没有
//明文分组1会和iv进行异或,得到密文分组1,再用明文分组2与上一次密文分组进行异或,以此类推
//所以我们看看哪里有异或的可能就是iv,iv在右
int __fastcall CWAESCipher::WBACRAES128_EncryptCBC(
        CWAESCipher *this,
        CSecFunctProvider *param,
        unsigned __int8 *a3,
        unsigned int *a4,
        bool a5)
{
  int result; // r0
  int v9; // r3
  int v10; // r7
  unsigned __int8 *v11; // r1
  int i; // r5
  unsigned __int8 *v13; // r4
  unsigned __int8 *v14; // r3
  char v15; // t1

  if ( a5 )
  {
  	//进行填充
    result = CSecFunctProvider::InsertCBCPadding(param, a3, a4, a4);
    if ( result )
      return result;
  }
  else if ( *(_DWORD *)a3 << 28 )
  {
    return 11;
  }
  if ( param )
  {
    v9 = 0;
    v10 = *(_DWORD *)a3 >> 4;
    do
    {
      *((_BYTE *)param + v9) ^= *((_BYTE *)this + v9 + 8);//只有这里像iv,第一次循环得到结果是00
      ++v9;
    }
    while ( v9 != 16 ); //循环16次,得到结果就是32个0
    v11 = (unsigned __int8 *)param;
    for ( i = 0; i != v10; ++i )
    {
      v13 = v11 + 16;
      v14 = v11;
      if ( i )
      {
        do
        {
          v15 = *v14++;
          *(v14 - 1) = v15 ^ *(v14 - 17);
        }
        while ( v14 != v13 );
      }
      //块加密
      result = CWAESCipher::WBACRAES_EncryptOneBlock(this, v11);
      v11 = v13;
      //判断是否全部加密完成,加密完成跳出循环
      if ( result )
        return result;
    }
  }
  return 0;
}
// 0x4dcc
在这里看不到函数了,进入汇编查看
int __fastcall CWAESCipher::WBACRAES_EncryptOneBlock(CWAESCipher *this, unsigned __int8 *a2, unsigned __int8 *a3)
{
  return (**(int (__fastcall ***)(CWAESCipher *, unsigned __int8 *, unsigned __int8 *, int))this)(this, a2, a3, 10);
}
发现汇编长这样 看到有一个BLX R4,hook这个寄存器的地址得到 0x4dcc
.text:0000582E                 PUSH            {R4,LR}
.text:00005830                 LDR             R3, [R0]
.text:00005832                 LDR             R4, [R3]
.text:00005834                 MOVS            R3, #0xA
.text:00005836                 BLX             R4
.text:00005838                 POP             {R4,PC}

第三个函数:主要加密位置

//先是进行了列表,然后开始9轮循环,然后进行最后一轮,赋值给a3,把结果返回
int __fastcall CWAESCipher_Auth::WBACRAES_EncryptOneBlock(
        CWAESCipher_Auth *this,
        CSecFunctProvider *a2,
        unsigned __int8 *a3,
        int a4)
{
  unsigned __int8 (*v5)[8]; // r3
  int i; // r11
  int v7; // r1
  int v8; // r3
  _DWORD *v9; // r6
  int j; // r2
  int v11; // r10
  int v12; // r0
  int v13; // r0
  _DWORD *v14; // r8
  int v15; // r0
  int k; // r2
  char *v17; // r3
  int m; // r9
  int v19; // r7
  char v20; // r5
  char v21; // r1
  int v22; // r6
  int v23; // r0
  unsigned int v24; // r5
  int v25; // r1
  char v26; // r8
  _DWORD *v27; // r12
  char v28; // r6
  int v29; // r12
  _DWORD *v30; // r8
  int v31; // r3
  int v32; // r12
  int v33; // r1
  int v34; // r0
  int n; // r2
  _DWORD *v36; // r7
  int v37; // r11
  char v38; // r11
  char *v39; // r6
  int v40; // r11
  int ii; // r3
  int jj; // r2
  int v44; // [sp+0h] [bp-E8h]
  int v45; // [sp+4h] [bp-E4h]
  int v46; // [sp+10h] [bp-D8h]
  _BYTE v50[4]; // [sp+38h] [bp-B0h] BYREF
  int v51; // [sp+3Ch] [bp-ACh]
  _DWORD s[42]; // [sp+40h] [bp-A8h] BYREF
  
  memset(s, 0, 0x20u);
  //根据下面的s操作猜测是state块,可以在这里进行DFA攻击
  v46 = CSecFunctProvider::PrepareAESMatrix(a2, (unsigned __int8 *)&word_10, (int)s, v5);// 列表
  if ( !v46 )
  {
    for ( i = 0; ; ++i )
    {
      if ( i >= a4 )
        goto LABEL_39;
      if ( i == 9 )  // 前9轮循环,9轮后退出,可以选择在这里进行注入进行攻击,然后主动调用当前函数
        break;
      v7 = 0;
      v8 = 0;
      v45 = 4 * i;
      do
      {
        v9 = &s[2 * v8 + 32];
        for ( j = 0; j != 4; ++j )
        {
          v11 = *((_DWORD *)this + 6);
          if ( v11 == 1 )
          {
            v15 = (*((_BYTE *)&unk_18D8E + v7) + (_BYTE)j) & 3;
            v51 = roundTables_auth1[256 * (v8 + 4 * (v15 + v45)) + *((unsigned __int8 *)v9 + v15 - 128)];
          }
          else
          {
            v12 = (*((_BYTE *)&unk_18D8E + v7) + (_BYTE)j) & 3;
            v13 = *((unsigned __int8 *)v9 + v12 - 128) + ((v8 + 4 * (v12 + v45)) << 8);
            if ( v11 == 2 )
              v14 = &roundTables_auth2_ptr;
            else
              v14 = &roundTables_auth1_ptr;
            v51 = *(_DWORD *)(*v14 + 4 * v13);
          }
          s[4 * v8 + 16 + j] = v51;
        }
        ++v8;
        v7 += 2;
      }
      while ( v8 != 4 );                        // v8  4字节端序
      for ( k = 0; k != 4; ++k )
      {
        v17 = (char *)&s[16] + k;
        for ( m = 0; m != 4; ++m )
        {
          v19 = 0;
          v20 = *v17;
          v50[1] = v17[16];
          v21 = v17[32];
          v22 = v20 & 0xF;
          v23 = 96 * i + 24 * m;
          v50[0] = v20;
          v50[2] = v21;
          v24 = v20 & 0xF0;
          v50[3] = v17[48];
          v25 = 6 * k;
          do
          {
            v26 = v50[++v19];
            if ( v11 == 2 )
              v27 = &xorTables_auth2_ptr;
            else
              v27 = &xorTables_auth1_ptr;
            v28 = *(_BYTE *)(*v27 + (v22 | (16 * (v26 & 0xF))) + ((v23 + v25) << 8));
            v29 = v25 + 1;
            v44 = v26 & 0xF0 | (v24 >> 4);
            v22 = v28 & 0xF;
            if ( v11 == 2 )
              v30 = &xorTables_auth2_ptr;
            else
              v30 = &xorTables_auth1_ptr;
            v25 += 2;
            v24 = (unsigned __int8)(16 * *(_BYTE *)(*v30 + v44 + ((v29 + v23) << 8)));
          }
          while ( v19 != 3 );
          v17 += 4;
          *((_BYTE *)&s[2 * k] + m) = v24 | v22;
        }
      }
    }
    if ( a4 == 10 )
    {
     //从这个代码可以看出s一直在做操作,猜测s是state块,然后赋值给a3,猜测a3是加密返回值
      s[8] = s[0];
      s[9] = s[1];
      s[10] = s[2];
      s[11] = s[3];
      s[12] = s[4];
      s[13] = s[5];
      s[14] = s[6];
      s[15] = s[7];
      v31 = 0;
      v32 = *((_DWORD *)this + 6);
      do
      {                                         // 第10轮
        v33 = 0;
        v34 = 0;
        for ( n = 0; n != 4; ++n )
        {
          if ( v32 == 1 )
          {
            v38 = *((_BYTE *)&unk_18D8E + v34);
          }
          else
          {
            if ( v32 == 2 )
            {
              v36 = &finalRoundTable_auth2_ptr;
              v37 = (*((_BYTE *)&unk_18D8E + v34) + (_BYTE)v31) & 3;
              goto LABEL_37;
            }
            v38 = *((_BYTE *)&unk_18D8E + v34);
          }
          v36 = &finalRoundTable_auth1_ptr;
          v37 = (v38 + (_BYTE)v31) & 3;
LABEL_37:
          v34 += 2;
          v39 = (char *)&s[2 * n + 32] + v37;
          v40 = n + 4 * v37;
          *((_BYTE *)s + v31 + v33) = *(_BYTE *)(*v36 + (unsigned __int8)*(v39 - 96) + (v40 << 8));
          v33 += 8;
        }
        ++v31;
      }
      while ( v31 != 4 );
    }
LABEL_39:
    for ( ii = 0; ii != 4; ++ii )
    {
      for ( jj = 0; jj != 4; ++jj )
        a3[4 * ii + jj] = *((_BYTE *)&s[2 * jj] + ii);// 结果在a3并返回
    }
  }
  return v46;
}

纯靠猜,我们分析一下哪里是md5的明文,确认s是明文

  sprintf(s, "%s%d", a2, v6);
  v7 = s;
  do
  {
    v8 = v7++;
    v9 = (unsigned __int8)*v8;
  }
  while ( *v8 );
  v674 = &v699;
  v672 = v8 - s;
  v703 = 8 * (v8 - s);
  v704 = (unsigned int)(v8 - s) >> 29;
  if ( (unsigned int)(v8 - s) > 0x3F )
  {
    if ( s != v705 )
    {
      if ( v705 >= s )
      {
        v15 = &v706;
        v16 = s + 64;  #首先s有+64比较像
        do
        {
          v17 = *((_DWORD *)v16 - 1);
          v16 -= 4;
          v18 = v16 == s;
          *(_DWORD *)v15 = v17;
          v15 -= 4;
        }
        while ( !v18 );
      }
      else
      {
        do
        {
          v13 = (char *)&v699 + v9;
          v14 = *(_DWORD *)&s[v9]; #s在do while循环里面,并且&s从地址里面一个个不停地取值,而且刚好是循环16次,md5的长度是16个字节,所以猜测s是明文
          v9 += 4;
          *((_DWORD *)v13 + 6) = v14;
        }
        while ( v9 != 64 );
      }
    }

md5返回值就更明显了,v652就是得,循环16次,每次2字节,就是32位

  for ( ii = 0; ii != 16; ++ii )
  {
    v652 = (char *)(v679 + 2 * ii);
    v653 = *((unsigned __int8 *)v698 + ii);
    sprintf(v652, "%02x", v653);
  }
  free(s);
  return 1;

unidbg主动调用和dfa攻击

package com.cloudy.linglingbang;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.Module;

import com.github.unidbg.arm.HookStatus;
import com.github.unidbg.arm.backend.Backend;
import com.github.unidbg.arm.backend.BackendException;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.debugger.BreakPointCallback;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.file.linux.AndroidFileIO;
import com.github.unidbg.hook.HookContext;
import com.github.unidbg.hook.ReplaceCallback;
import com.github.unidbg.hook.hookzz.HookZz;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.jni.ProxyClassFactory;
import com.github.unidbg.linux.android.dvm.jni.ProxyDvmObject;
import com.github.unidbg.linux.file.ByteArrayFileIO;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.memory.MemoryBlock;
import com.github.unidbg.pointer.UnidbgPointer;
import com.github.unidbg.spi.LibraryFile;
import com.github.unidbg.unix.UnixSyscallHandler;
import com.github.unidbg.utils.Inspector;
import com.sun.jna.Pointer;
import org.apache.commons.codec.DecoderException;

import unicorn.ArmConst;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import static unicorn.ArmConst.UC_ARM_REG_R0;

public class Cloud extends AbstractJni  implements  IOResolver  {
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;

    private final DvmClass CheckCodeUtil;

    private final Memory memory;

    private final DalvikModule dvm;
    public Cloud(){
        emulator = AndroidEmulatorBuilder.for32Bit()
                .setProcessName("com.cloudy.linglingbang")
                .build(); // 创建模拟器实例,要模拟32位或者64位,在这里区分
        memory = emulator.getMemory(); // 模拟器的内存操作接口
        memory.setLibraryResolver(new AndroidResolver(23)); // 设置系统类库解析
		//这个可以对文件进行访问
        //emulator.getSyscallHandler().addIOResolver(this);
        vm = emulator.createDalvikVM(new File("D:\\lingdian\\java-project\\unidbg-0.9.7\\unidbg-android\\src\\test\\java\\com\\Cloud\\apk\\cloud.apk")); // 创建Android虚拟机
        vm.setVerbose(true); // 设置是否打印Jni调用细节
        vm.setJni(this);
        dvm = vm.loadLibrary(new File("D:\\lingdian\\java-project\\unidbg-0.9.7\\unidbg-android\\src\\test\\java\\com\\Cloud\\apk\\libencrypt.so"), true); // 加载libttEncrypt.so到unicorn虚拟内存,加载成功以后会默认调用init_array等函数
        module = dvm.getModule(); // 加载好的libttEncrypt.so对应为一个模块
        vm.callJNI_OnLoad(emulator,module);
        CheckCodeUtil = vm.resolveClass("com/bangcle/comapiprotect/CheckCodeUtil");
	    Debugger attach = emulator.attach();
        setDebugger(attach);
    }
    public static int randInt(int min, int max) {
        Random rand = new Random();
        return rand.nextInt((max - min) + 1) + min;
    }
    public Cloud(AndroidEmulator emulator, VM vm, Module module, DvmClass checkCodeUtil, Memory memory, DalvikModule dvm) {
        this.emulator = emulator;
        this.vm = vm;
        this.module = module;
        CheckCodeUtil = checkCodeUtil;
        this.memory = memory;
        this.dvm = dvm;
    }
    public DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg){
        switch (signature){
            case "android/app/ActivityThread->currentActivityThread()Landroid/app/ActivityThread;":
                return vm.resolveClass("android/app/ActivityThread").newObject(null);
            case "android/os/SystemProperties->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;":
                String string = varArg.getObjectArg(0).getValue().toString();
               // System.out.println(string);
                if("ro.serialno".equals(string)){
                    return new StringObject(vm,"unknown");
                }
        }
        return super.callStaticObjectMethod(vm, dvmClass, signature, varArg);
    }
    public DvmObject<?> callObjectMethod(BaseVM vm, DvmObject<?> dvmObject, String signature, VarArg varArg) {
        switch (signature){
            case "android/app/ActivityThread->getSystemContext()Landroid/app/ContextImpl;":
                return vm.resolveClass("android/app/ContextImpl").newObject(null);
            case "android/app/ContextImpl->getPackageManager()Landroid/content/pm/PackageManager;":
                return vm.resolveClass("android/content/pm/PackageManager").newObject(null);
            case "android/app/ContextImpl->getSystemService(Ljava/lang/String;)Ljava/lang/Object;":
                String string = varArg.getObjectArg(0).getValue().toString();
                //System.out.println(string);
                return vm.resolveClass("android.net.wifi").newObject(signature);
            case "android/net/wifi->getConnectionInfo()Landroid/net/wifi/WifiInfo;":
                return vm.resolveClass("android/net/wifi/WifiInfo").newObject(null);
            case "android/net/wifi/WifiInfo->getMacAddress()Ljava/lang/String;":
                return new StringObject(vm,"02:00:00:00:00:00");
        }
        return super.callObjectMethod(vm,dvmObject,signature,varArg);
    }
	
    FileResult<AndroidFileIO> f1;
    //补文件访问,补了这个发现还有堆栈检测,就没补了
    public FileResult<AndroidFileIO> getF1(String pathname, int oflags) {
        if (f1 == null) {
            f1 = FileResult.<AndroidFileIO> success(new ByteArrayFileIO(oflags, pathname, "com.cloudy.linglingbang".getBytes()));
        }
        return f1;
    }

    @Override
    public FileResult<AndroidFileIO> resolve(Emulator emulator, String pathname, int oflags) {
        if ("/proc/self/cmdline".equals(pathname) || ("/proc/" + emulator.getPid() + "/cmdline").equals(pathname)) {
            return getF1(pathname, oflags);
        }
        return null;
    }
    public DvmObject<?> getStaticObjectField(BaseVM vm, DvmClass dvmClass, String signature) {
        switch (signature) {
            case "android/os/Build->MODEL:Ljava/lang/String;": {
                return new StringObject(vm, "Pixel 4 XL");
            }
            case "android/os/Build->MANUFACTURER:Ljava/lang/String;": {
                return new StringObject(vm, "Google");
            }
            case "android/os/Build$VERSION->SDK:Ljava/lang/String;": {
                return new StringObject(vm, "29");
            }
        }
        return super.getStaticObjectField(vm,dvmClass,signature);
    }
    public void decheckcode(String str){
        DvmObject ret = CheckCodeUtil.callStaticJniMethodObject(emulator,"decheckcode(Ljava/lang/String;)Ljava/lang/String;",str);
        System.out.println("\ncall decheckcode: " + ret.getValue().toString());
    }
    public void patch(){
    	//解密的异常分支
        UnidbgPointer pointer = UnidbgPointer.pointer(emulator,module.base + 0x16604);
        byte[] code = new byte[]{(byte) 0x20, (byte) 0xB1};
        pointer.write(code);
        //把0x13FC6地址的r0寄存器改为1,不改的话会走异常分支,加密的异常分支
        UnidbgPointer pointer1 = UnidbgPointer.pointer(emulator, module.base + 0x13FC6);
        byte[] code1 = new byte[]{(byte) 0x20, (byte) 0x01}; // MOVS R0, #1 的 Thumb 编码
        pointer1.write(code1);
    }
    public static byte[] hexStringToBytes(String hexString) {
        int len = hexString.length();
        if (len % 2 != 0) {
            throw new IllegalArgumentException("Invalid hex string");
        }
        byte[] result = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            result[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return result;
    }
    public static String bytesToHexString(byte... src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }
    public void call(){
    	//这种主动调用是调用当前函数的,感觉还是不推荐。如果有些东西,在函数之前进行初始化的就废了
        MemoryBlock inBlock=emulator.getMemory().malloc(16,true);
        UnidbgPointer inptr = inBlock.getPointer();
        MemoryBlock outBlock=emulator.getMemory().malloc(16,true);
        UnidbgPointer outPtr = outBlock.getPointer();
        MemoryBlock inBlock1=emulator.getMemory().malloc(16,true);
        UnidbgPointer inptr1 = inBlock1.getPointer();
        byte[] hellos = hexStringToBytes("68656c6c6f");
        inptr.write(0,hellos,0,hellos.length);
        byte[] args1 = hexStringToBytes("C0AD0140");
        inptr1.write(0,args1,0,args1.length);
        //参数1是未知,参数2是参数,参数3返回值,参数4未知
        module.callFunction(emulator,0x4DCC+1,inptr1,inptr,outPtr,0xa);
        String ret=bytesToHexString(outPtr.getByteArray(0,0x10));
        System.out.println("white box result:"+ ret);
        inBlock.free();
        outBlock.free();
    }

    public String call_checkcode() {
    	//unidbg主动调用地址
        List<Object> args = new ArrayList<>(10);
        args.add(vm.getJNIEnv());
        args.add(0);
        String string = "mobile=17637693656&password=lv946346&client_id=2019041810222516127&client_secret=c5ad2a4290faa3df39683865c2e10310&state=FnCNm2C3bS&response_type=token";
        args.add(vm.addLocalObject(new StringObject(vm, string)));
        args.add(2);
        args.add(vm.addLocalObject(new StringObject(vm, "1734243230657")));
        Number number = module.callFunction(emulator, 0x13A18+1, args.toArray());
        String result = vm.getObject(number.intValue()).getValue().toString();
        return result;
    }
    public void jni_call(){
        //jni调用java层主动调用,推荐
        String str1 = "mobile=17637693632&password=lv946346&client_id=2019041810222516127&client_secret=c5ad2a4290faa3df39683865c2e10310&state=FnCNm2C3bS&response_type=token";
        str1="hello";
        String str3 = "1734243230657";
        DvmObject ret = CheckCodeUtil.callStaticJniMethodObject(emulator, "checkcode(Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;",str1,1,str3);
        String strOut = (String)ret.getValue();
        System.out.println("call checkcode: " + strOut);
    }
    public void setDebugger(Debugger debugger){
        //emulator.attach().addBreakPoint(module.base+0x5836);//下断点看跳得地址是哪里
        //c是放开debug mr0是读取r0寄存器得值(32位),x0是64位
        //emulator.traceRead(0x403b1000,0x403b1010);//看有哪些地方对明文进行读取
        debugger.addBreakPoint(module.base+0x5A34, new BreakPointCallback() {
            @Override
            public boolean onHit(Emulator<?> emulator, long address) {
                String fakeInput = "hello";//把明文重新改为短一点字符
                int length = fakeInput.length();
                MemoryBlock fakeInputBlock = emulator.getMemory().malloc(length, true);
                fakeInputBlock.getPointer().write(fakeInput.getBytes(StandardCharsets.UTF_8));
                // 修改r0为指向新字符串的新指针
                emulator.getBackend().reg_write(ArmConst.UC_ARM_REG_R0, fakeInputBlock.getPointer().peer);
                return true;
            }
        });
        //进行dfa攻击
        debugger.addBreakPoint(module.base+0x4E26+1, new BreakPointCallback() {
            int round = 0;
            //0xbffff678,这个地址是state块的地址,把debug打上看看state块的地址是多少,记住明文不能变,变了state块地址就会变
            UnidbgPointer statePointer = memory.pointer(0xbffff678);
            @Override
            public boolean onHit(Emulator<?> emulator, long address) {
                round += 1;
                if (round % 9 == 0){
                    statePointer.setByte(randInt(0, 15), (byte) randInt(0, 0xff));
                }
                return true;//返回true 就不会在控制台断住
            }
        });
        //这里是hook,sprintf,得到地址和入参,0x301C需要去so里面找一下
        debugger.addBreakPoint(module.base+0x301C+1, new BreakPointCallback() {
            @Override
            public boolean onHit(Emulator<?> emulator, long address) {
                RegisterContext context = emulator.getContext();
                Pointer input = context.getPointerArg(1);
                Pointer input2 = context.getPointerArg(2);
                Pointer input3 = context.getPointerArg(3);
                Inspector.inspect(input.getByteArray(0, 0x20), "sprintf arg1");
                try{
                    Inspector.inspect(input2.getByteArray(0, 0x20), "sprintf arg2");
                }catch (BackendException e){
                    System.out.println("input2出现异常 hashcode:"+input2.hashCode());
                }
                try {
                    Inspector.inspect(input3.getByteArray(0, 0x20), "sprintf arg3");
                }catch (BackendException e){
                    System.out.println("input  arg3出现异常 hashcode:"+input3.hashCode());
                }
                Inspector.inspect(input3.toString().getBytes(StandardCharsets.UTF_8), "input  arg3 addr");
                Inspector.inspect(context.getLRPointer().toString().getBytes(StandardCharsets.UTF_8), "lr addr");
                return true;
            }
        });
    }
    public static void main(String[] args) {
        Cloud cloud = new Cloud();
        cloud.patch();
        String res=cloud.call_checkcode();
        System.out.println(res);
        cloud.decheckcode(res);
    }

计算正确秘钥

import phoenixAESwith 
# 创建tracefile文件,第一行是正确密文 后面是故障密文    
phoenixAES.crack_file('tracefile', [], True, False, 3)
拿到结果了,用aes_keyschedule把主密钥也就是初始秘钥还原出来
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值