jeb打开apk
验证为:gogogoJNI.check_key(MainActivity.this.eText1.getText().toString()) == 1
public class gogogoJNI {
public gogogoJNI() {
super();
}
public static native int check_key(String arg0) {
}
public static native String sayHello() {
}
}
IDA打开so 来到check_key
signed int __fastcall Java_com_example_assemgogogo_gogogoJNI_check_key(_JNIEnv *env, jobject job, String s)
{
_JNIEnv *env_1; // r5
String s_1; // r6
signed int result; // r8
int str; // r0
int str_; // r4
unsigned int i; // r5
int rand_n; // r0
int p_char; // r1
int v11; // r0
env_1 = env;
s_1 = s;
result = 0;
str = ((int (__fastcall *)(_JNIEnv *, String, _DWORD))env->functions->GetStringUTFChars)(env, s, 0);
if ( str )
{
str_ = str;
((void (__fastcall *)(_JNIEnv *, String, int))env_1->functions->ReleaseStringUTFChars)(env_1, s_1, str);
srand(0x32u);
for ( i = 0; i <= 31; ++i )
{
rand_n = rand();
p_char = *(unsigned __int8 *)(str_ + i);
v11 = rand_n % 128 - (unsigned __int8)aD584a68d4e213d[i];// d584a68d4e213d88w511v48e61g8d6e8
}
close(sock_fd_g);//可疑
result = 1;
}
return result;
发现只要输入不为空即返回1,所以真正的验证点不在这里
同时看到了close(sock_fd_g);这个可疑点,这是关闭soket通信
向上层查看
signed int JNI_OnLoad()
{
j_inti_proc();
return 65540;
}
int j_inti_proc(void)
{
return inti_proc();
}
int inti_proc()
{
char *v0; // r0
signed int v1; // r1
signed int i; // r6
struct addrinfo **v3; // r0
int sk; // r4
struct addrinfo *v5; // r5
int result; // r0
int arg; // [sp+8h] [bp-70h]
int v8; // [sp+Ch] [bp-6Ch]
int v9; // [sp+10h] [bp-68h]
struct addrinfo *pai; // [sp+14h] [bp-64h]
struct addrinfo req; // [sp+18h] [bp-60h]
char v12[32]; // [sp+38h] [bp-40h]
int v13; // [sp+58h] [bp-20h]
v0 = mm0;
v1 = 34291;
v9 = 1;
while ( v1 )
{
--v1;
*v0 ^= 0x67u;
++v0;
}
i = 1;
*(_QWORD *)&req.ai_protocol = 0LL;
*(_QWORD *)&req.ai_addr = 0LL;
req.ai_family = 0;
req.ai_flags = 1;
req.ai_socktype = 1;
req.ai_next = 0;
if ( getaddrinfo(0, "8000", &req, &pai) )
goto LABEL_19;
v3 = &pai;
i = 1;
while ( 1 )
{
v5 = *v3;
if ( !*v3 )
{
i = 2;
goto LABEL_19;
}
sk = socket(v5->ai_family, v5->ai_socktype, v5->ai_protocol);
if ( sk != -1 )
break;
LABEL_10:
v3 = &v5->ai_next;
}
if ( setsockopt(sk, 1, 2, &v9, 4u) == -1 )
goto LABEL_19;
if ( bind(sk, (const struct sockaddr *)v5->ai_canonname, v5->ai_addrlen) == -1 )
{
close(sk);
goto LABEL_10;
}
freeaddrinfo(pai);
if ( listen(sk, 128) == -1 )
{
i = 1;
}
else
{
for ( i = 0; i != 32; i += 4 )
{
arg = sk;
v8 = 0;
pthread_create((pthread_t *)&v12[i], 0, (void *(*)(void *))nullsub_, &arg);//关键点
}
sock_fd_g = sk;
}
LABEL_19:
result = _stack_chk_guard - v13;
if ( _stack_chk_guard == v13 )
result = i;
return result;
}
可以看到其关键操作为soket和创建线程,线程运行函数为nullsub_
void __fastcall __noreturn nullsub_(int *sk)
{
int *v1; // r4
int v2; // r5
char *v3; // r1
size_t v4; // r0
size_t v5; // r0
char v6; // [sp+Eh] [bp-C422h]
char buf; // [sp+C35Eh] [bp-D2h]
socklen_t addr_len; // [sp+C38Ch] [bp-A4h]
struct sockaddr addr; // [sp+C390h] [bp-A0h]
v1 = sk;
addr_len = 128;
while ( 1 )
{
do
v2 = accept(*v1, &addr, &addr_len);
while ( v2 == -1 );
v3 = &addr.sa_data[6];
if ( addr.sa_family == 2 )
v3 = &addr.sa_data[2];
inet_ntop(addr.sa_family, v3, &buf, 0x2Eu);
v4 = strlen(mm0);
snprintf(
&v6,
0xC350u,
"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %ld\r\n\r\n%s",
v4,
mm0);
v5 = strlen(&v6);
if ( send(v2, &v6, v5, 0) == -1 )
perror("send");
close(v2);
}
}
可以看出是传递了一个网页,关键数据为mm0
查看交叉引用,发现在inti_proc()开始处有如下操作:
v0 = mm0;
v1 = 34291;
v9 = 1;
while ( v1 )
{
--v1;
*v0 ^= 0x67u;
++v0;
}
mm0处34291长度的数据异或0x67
dump出数据,恢复出html网页。
发现使用了wasm,逆向一波,参考https://www.anquanke.com/post/id/179556
// set_input_flag(value[ii].charCodeAt(),ii) ii-->[0-32]
__int64 __fastcall set_input_flag(char char_code, int index)
{
if ( ++wasm_rt_call_stack_depth > 500u )
wasm_rt_trap(7LL);
i32_store8((__int64)&memory, (unsigned int)(index + 1024), char_code);
--wasm_rt_call_stack_depth;
return 0LL;
}
输入保存到偏移1024处
__int64 check_key()
{
unsigned int v0; // ST00_4
if ( ++wasm_rt_call_stack_depth > 0x1F4u )
wasm_rt_trap(7LL);
o(1024u, 0x401u, 0x402u, 0x403u); // 每次取4个输入,进行相应异或
oo(0x404u, 0x405u, 0x406u, 0x407u);
ooo(0x408u, 0x409u, 0x40Au, 0x40Bu);
oooo(0x40Cu, 0x40Du, 0x40Eu, 0x40Fu);
ooooo(0x410u, 0x411u, 0x412u, 0x413u);
oooooo(0x414u, 0x415u, 0x416u, 0x417u);
ooooooo(0x418u, 0x419u, 0x41Au, 0x41Bu);
oooooooo(0x41Cu, 0x41Du, 0x41Eu, 0x41Fu);
v0 = xxx();
--wasm_rt_call_stack_depth;
return v0;
}
o函数内为对不同位进行异或操作
xxx()函数 解32元一次方程(可以搜一下z3求解器,很强),结果分别再进行对应的异或操作,
整理得出答案:K9nXu3_2o1q2_w3bassembly_r3vers3
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界