记一道热修改汇编,并且伴有反调试以及使用爆破解的题目.这道题不难,但是很有意思.
0x1 ptrace反调试
- 程序的so层的
anti_debug
在使用ptrace
进行反调试,这里直接修改16进制汇编进行反调试
- 这里的 0x11 时随便写的
0x2 热修改smali代码
- 这个程序使用
/proc/{pid}/maps
的方式获取dex文件在内存中地址 - 然后直接修改内存中关于
what
函数的二进制实现代码
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
发现 当 checkFormat 和 checksn 都为真时 表示校验正确,并且 密钥长度为 26 字节
- checkFormat
分析该函数 得出结论:
- Flagde [0,4]= flag{
- Flagde [25]=” }”
- Checksn
将输入的密钥 进行 encode 运算,最后与 内置密钥 str_key 相等 就表示flag正确
- encode 算法
算法中 涉及大量的 this.wat 运算 - Dex中的 this what
- 修复后的 whis what
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===============");
}