美文网首页@IT·互联网
csdn 样本9 blackbox 后2个加密字符的生成还原

csdn 样本9 blackbox 后2个加密字符的生成还原

作者: feng504x | 来源:发表于2021-11-05 11:55 被阅读0次

    前5个加密字符还原, 请看龙哥的文章

    SO逆向入门实战教程九——blackbox
    https://blog.csdn.net/qq_38851536/article/details/118115569

    打开ida, 从sub_3B3C方法继续向下分析


    1.png

    我们一步一步看:

    首先是v19的赋值

    uint8x8_t v19; // d16 v19.n64_u32[1] = *(_DWORD *)"6789BCDFGHJKRTVWMNPQ567";

    uint8x8_t 的结构体如下:

    这里用到了 ARM NEON 编程
    https://www.cnblogs.com/xylc/p/5410517.html

    2.png

    DCD 4个字节

    DCW 2个字节

    DCB 1个字节

    DCQ 8个字节

    // v35就是前5个加密字节 v19.n64_u32[0] = *(_DWORD *)&v35[1];

    这一步将上面得到的后4个字节的加密值赋值给 n64_u32[0]

    就是上边的CD2D

    备注: CD2D 是从上一部分内容获取的, 请查看前半部分的内容
    https://blog.csdn.net/qq_38851536/article/details/118115569

    uint32x4_t v34; // [sp+20h] [bp-168h] BYREF //寄存器中的每个元素的长度都扩展为原来的两倍,u8扩展为u16 v34 = vmovl_u16((uint16x4_t)vmovl_u8(v19).n128_u64[0]);

    分为以下4步:

    1. vmovl_u8对读取的uint8x8进行宽度扩展

    vmovl_u8() 将uint8x8_t --> uint16x8_t

    这句的作用是 //convert to 16-bit and move to 128-bit reg

    CD2D 由原来的每个字符一个字节, 变成一个字符2个字节, 高位补0

    1. 然后取前n128_u64[0], 即取前64位数据

    .n128_u64[0]”这个地方,根据IDA的解析规则,这代表一个128位的数据只取前64位,如果是“.n128_u64[1]”的话就是取后64位

    1. 然后 使用(uint16x4_t) 强转成 uint16x4_t 类型

    这句的作用是 //get low 64 bit and move them to 64-bit reg

    1. 最后 vmovl_u16 对读取的uint16x4进行宽度扩展

    vmovl_u16() 将uint16x4_t --> uint32x4_t

    CD2D 由原来的每个字符2个字节, 变成一个字符4个字节, 高位补0

    参考文档:

    然后将拓展后的数据传入 sub_194C() 方法

    在unidbg debugger 传到sub_194C方法是这样的


    3.png

    分析 sub_194C()


    4.png 5.png

    看上去调用了很多方法, 其实也没有什么 直接用java还原即可

    下面放出代码:

    public static int[] sub_194C(int[] a1) { int v1; int v3; int v4; int v5; int v6; int v7; int v8; int v9; int v18; int v23; int v24; int v22; int v21; int v20; int v19; int v10; int v11; int v12; int v13; int v14; int v15; int v16; v1 = a1[0]; v3 = sub_191E(v1); v4 = a1[1]; v24 = v3; v5 = (2 * v4) ^ 0x1B; if ( (v4 & 0x80) == 0 ){ v5 = 2 * v4; } v18 = v5 ^ v4; v23 = sub_18F8(v4); v6 = a1[2]; v22 = sub_18D4(v6); v7 = a1[3]; v21 = sub_191E(v4); v20 = sub_18F8(v6); v19 = sub_18D4(v7); v8 = v18 ^ sub_18D4(v1); v9 = v8 ^ sub_191E(v6); v10 = v9 ^ sub_18F8(v7); v11 = sub_18F8(v1); v12 = sub_18D4(v4); v13 = sub_191E(v7); a1[2] = v10 & 0xff; v14 = (2 * v1) ^ 0x1B; if ( (v1 & 0x80) == 0 ){ v14 = 2 * v1; } a1[1] = (v14 ^ v1 ^ v21 ^ v20 ^ v19) & 0xff; v15 = (2 * v7) ^ 0x1B; if ( (v7 & 0x80) == 0 ){ v15 = 2 * v7; } a1[0] = (v15 ^ v24 ^ v23 ^ v22 ^ v7) & 0xff; v16 = (2 * v6) ^ 0x1B; if ( (v6 & 0x80) == 0 ){ v16 = 2 * v6; } a1[3] = (v13 ^ v16 ^ v6 ^ v11 ^ v12) & 0xff; return a1; } public static int sub_191E(int a1) { boolean v2; int v3; int v4; v2 = (a1 & 0x80) != 0; v3 = (2 * a1) ^ 0x1b; if(!v2){ v3 = 2 * a1; } v4 = v3 ^ a1 ^ sub_18F8(a1); return sub_18D4(a1) ^ v4; } public static int sub_18F8(int a1) { int v1; int v2; v1 = (2 * a1) ^ 0x1b; if((a1 & 0x80) == 0){ v1 = 2 * a1; } v2 = (2 * v1) ^ 0x1b; if((v1 & 0x80) == 0){ v2 = 2 * v1; } return sub_18D4(v2 ^ v1); } public static int sub_18D4(int a1) { int v1; int v2; v1 = (2 * a1) ^ 0x1b; if((a1 & 0x80) == 0){ v1 = 2 * a1; } v2 = (2 * v1) ^ 0x1b; if((v1 & 0x80) == 0){ v2 = 2 * v1; } return v2 ^ v1; }

    这里要注意的是:

    算出来的数只取 低8位, 这个是通过调试知道的

    调用sub_194C方法前:

    6.png

    CD2D

    调用sub_194C方法后:

    7.png

    继续向下分析:

    调用了sub_3864 方法

    8.png

    因为参数a2固定是100, 其实是调用了sub_37A4方法

    9.png

    sub_37A4 方法前面实现过了

    继续向下走:

    10.png

    查看汇编流发现, sub_37A4 计算的结果还做了 乘法和减法的操作

    11.png

    对应的java代码:

    传入参数是sub_194C的返回值

    public static String getLast2(int[] v25){ // int[] v25 = new int[]{0x58,0xEB,0x45,0xF6}; int v26 = 0; int v28; int v29; String v29Str; for ( int i = 0; i != 4; ++i ) { v28 = v25[i]; v26 += v28; } System.out.println(v26); // 算出ida中 sprintf的v29, 这一步要看汇编 int a2 = 100; v29 = v26 - sub_37A4(v26, a2) * a2; // System.out.println(Integer.toHexString(v29)); // 处理v29 if (v29 > 100){ v29 = v29 % 100; } if (v29 < 10){ v29Str = "0" + v29; }else{ v29Str = "" + v29; } return v29Str; }

    至此算法还原完成

    下面验证算法

    对比unidbg调用so生成的加密值和还原算法的加密值, 看是否相等

    public static void main(String[] args) throws Exception { // 打印详细日志 // Logger.getLogger("com.github.unidbg.linux.ARM32SyscallHandler").setLevel(Level.DEBUG); // Logger.getLogger("com.github.unidbg.unix.UnixSyscallHandler").setLevel(Level.DEBUG); // Logger.getLogger("com.github.unidbg.AbstractEmulator").setLevel(Level.DEBUG); // Logger.getLogger("com.github.unidbg.linux.android.dvm.DalvikVM").setLevel(Level.DEBUG); // Logger.getLogger("com.github.unidbg.linux.android.dvm.BaseVM").setLevel(Level.DEBUG); // Logger.getLogger("com.github.unidbg.linux.android.dvm").setLevel(Level.DEBUG); // PrintStream out = null; CrackBlackBox obj = new CrackBlackBox(); // 加密的key的明文 String keyText = "r0env"; for(int i = 0; i<10000; i += 1){ double d = Math.random(); int temp = (int)(d*1000000); if(! obj.callEncode(temp, keyText).equals(utils.encode(temp, keyText))){ System.out.println("两种方法的加密值不一样!!!!!!!!!!!!!!"); }; } obj.destroy(); }

    日志如下:

    unidbg调用so生成的加密值是: G7WJW18 [0, 0, 0, 0, 0, 3, -44, 7] hmacsha1加密值: 4e83863c0704078a26eF1Fb36b23905685ed2Fa4 索引值是: 4 前5个加密字节是: G7WJW 518 后2个加密字节是: 18 本地还原方法的最终加密值是: G7WJW18 unidbg调用so生成的加密值是: QRDH338 [0, 0, 0, 0, 0, 11, 25, 82] hmacsha1加密值: 1875d19268Fc156d09e0b4726e5bedFFbFca37ca 索引值是: 10 前5个加密字节是: QRDH3 638 后2个加密字节是: 38 本地还原方法的最终加密值是: QRDH338 unidbg调用so生成的加密值是: WXHGV98 [0, 0, 0, 0, 0, 8, 28, -87] hmacsha1加密值: 6d78a4050698aa9Fb20764321ad0b23bbFF53a0c 索引值是: 12 前5个加密字节是: WXHGV 398 后2个加密字节是: 98 本地还原方法的最终加密值是: WXHGV98 ....

    算法验证成功

    相关文章

      网友评论

        本文标题:csdn 样本9 blackbox 后2个加密字符的生成还原

        本文链接:https://www.haomeiwen.com/subject/fmqrzltx.html