首页
社区
课程
招聘
[原创]第五题:丛林的秘密
2019-6-21 20:33 3434

[原创]第五题:丛林的秘密

2019-6-21 20:33
3434
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世界

上传的附件:
收藏
点赞3
打赏
分享
最新回复 (1)
雪    币: 546
活跃值: (582)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
System32 2020-11-13 12:38
2
0
可以加你微信吗
游客
登录 | 注册 方可回帖
返回