记一道热修改汇编,并且伴有反调试以及使用爆破解的题目.这道题不难,但是很有意思.

0x1 ptrace反调试

  • 程序的so层的anti_debug在使用ptrace进行反调试,这里直接修改16进制汇编进行反调试

1.png
2.png

  • 这里的 0x11 时随便写的

0x2 热修改smali代码

  • 这个程序使用/proc/{pid}/maps的方式获取dex文件在内存中地址
    3.png
  • 然后直接修改内存中关于what函数的二进制实现代码

4.png

0x3 修复dex

  • JNI_OnLoad函数的末尾对内存中的dex文件进行dmp就可以获得修复后的dex文件
  • 此时的dex才是真正的代码

dmp代码如下

static main(void)
{
    auto fp, begin,size;
    fp = fopen("dump.bin", "wb");
    begin = 0x98340000;
    size = 0x98566000-begin;
    savefile(fp,0,begin,size);
}

0x4 wp

从 MainActivity 中发现 关键的比对函数 public boolean mainCheck(String str_in)

当函数返回 真时,表示falg正确

观察 mainCheck
11.png
发现 当 checkFormat 和 checksn 都为真时 表示校验正确,并且 密钥长度为 26 字节

  • checkFormat
    12.png

分析该函数 得出结论:

  1. Flagde [0,4]= flag{
  2. Flagde [25]=” }”
  • Checksn
    13.png

将输入的密钥 进行 encode 运算,最后与 内置密钥 str_key 相等 就表示flag正确

  • encode 算法
    14.png
    算法中 涉及大量的 this.wat 运算
  • Dex中的 this what
    15.png
  • 修复后的 whis what
    16.png

0x5 解密代码

  • 通过算法穷举出 encode 最终的密钥为 1chunq1u_n1c3_dalv1k
  • 也就是说flag 为: flag{1chunq1u_n1c3_dalv1k}

具体代码如下:

// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <stdio.h>
#include <string.h>

//加密后的密钥
unsigned char key_encrypt[] = {
0x65,
0x2B,
0x21,
0x26,
0x11,
0x38,
0x62,
0xA,
0x11,
0x21,
0x65,
0x1C,
0x75,
0x13,
0x25,
0x26,
0x2B,
0x31,
0x76,
0x2C
};

//what 算法
unsigned char what (unsigned char arg3, unsigned char arg4)
{
    return ((char)((arg3 ^ -1) & (arg4 ^ -1)));
}

//对应 源码中的 decode
void xor_20 (unsigned char*hex_in, int size)
{
    do
    {
        hex_in[size] ^= 32;
    } while (--size >= 0);
}

//获取 加密后的 flag
//比对时 使用
unsigned char*get_encrypt_flag ()
{
    //预处理
    xor_20 (key_encrypt, sizeof (key_encrypt));
    for (int i = 0; i < 20; i++)
    {
        printf ("0x%02x,", key_encrypt[i]);
    }
    puts ("");

    return key_encrypt;
}

//根据 encrypt_flag 和 标志flag  穷举出 正确的flag
unsigned char decrypt_flag (unsigned char encrypt_flag, int n_mark_flag)
{
    unsigned char mark_flag[] = "this_is_not_flaggggg";
    unsigned char b = mark_flag[n_mark_flag];

    for (unsigned char i = 33; i < 128; i++)
    {
        unsigned char dst_key = encrypt_flag;
        unsigned char res = what (what (what (b, b), what (i, i)), what (b, i));

        if (res == dst_key)
        {
            return i;
        }
    }
    return '#';
}

void decrypt ()
{
    unsigned char * decrypt_key = get_encrypt_flag ();

    for (int i = 0; i < 20; i++)
    {
        unsigned char key = decrypt_flag (decrypt_key[i], i);
        //printf ("%d: 0x%02x char:%c   \r\n", i, key, key);
        printf ("%c", key);
    }
    printf ("\r\n");
}

void main (int argc, unsigned char const *argv[])
{
    decrypt ();
    puts ("===============end===============");
} 
Last modification:August 25, 2021
如果觉得我的文章对你有用,请随意赞赏