2019ISCC Mobile

0x01 Mobile1

用Android killer载入找到入口函数

package com.iscc.crackme;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity
  extends AppCompatActivity
{
  static
  {
    System.loadLibrary("native-lib");
  }
  
  private boolean checkFirst(String paramString)
  {
    if (paramString.length() != 16) {
      return false;
    }
    int i = 0;
    while (i < paramString.length()) {
      if (paramString.charAt(i) <= '8')
      {
        if (paramString.charAt(i) < '1') {
          return false;
        }
        i += 1;
      }
      else
      {
        return false;
      }
    }
    return true;
  }
  
  public native boolean checkSecond(String paramString);
  
  protected void onCreate(final Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    setContentView(2131296284);
    paramBundle = (EditText)findViewById(2131165240);
    ((Button)findViewById(2131165218)).setOnClickListener(new View.OnClickListener()
    {
      public void onClick(View paramAnonymousView)
      {
        paramAnonymousView = paramBundle.getText().toString().trim();
        if ((MainActivity.this.checkFirst(paramAnonymousView)) && (MainActivity.this.checkSecond(paramAnonymousView)))
        {
          Toast.makeText(MainActivity.this, "注册成功!", 0).show();
          return;
        }
        Toast.makeText(MainActivity.this, "注册失败!", 0).show();
      }
    });
  }
}

代码非常简单,对注册码进行两次check,第一次check是

  private boolean checkFirst(String paramString)
  {
    if (paramString.length() != 16) {
      return false;
    }
    int i = 0;
    while (i < paramString.length()) {
      if (paramString.charAt(i) <= '8')
      {
        if (paramString.charAt(i) < '1') {
          return false;
        }
        i += 1;
      }
      else
      {
        return false;
      }
    }
    return true;
  }
  

功能是check注册码是否为16位,以及注册码是否为1~8的数字组合
第二个check函数在native层,分析so文件

 public native boolean checkSecond(String paramString);

用ida64载入64位的so文件,观察入口函数伪代码

char __fastcall Java_com_iscc_crackme_MainActivity_checkSecond(__int64 a1, __int64 a2, __int64 a3)
{
  char result; // al
  char v4; // [rsp+6h] [rbp-8Ah]
  char v5; // [rsp+13h] [rbp-7Dh]
  char v6; // [rsp+40h] [rbp-50h]
  char v7; // [rsp+58h] [rbp-38h]
  char v8; // [rsp+70h] [rbp-20h]
  unsigned __int64 v9; // [rsp+88h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  jstring2str(&v8, a1, a3);
  v5 = 0;
  std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::basic_string(&v7, &v8);
  v4 = 0;
  if ( checkfirst((__int64)&v7) & 1 )
  {
    std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::basic_string(&v6, &v8);
    v5 = 1;
    v4 = checkAgain(&v6);
  }
  if ( v5 & 1 )
    std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::~basic_string(&v6);
  std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::~basic_string(&v7);
  std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::~basic_string(&v8);
  result = v4 & 1;
  if ( __readfsqword(0x28u) == v9 )
    result = v4 & 1;
  return result;
}

发现也进行了两次check分别是checkfirst 以及 checkAgain,所以只要过了这两个check就完事了
值得注意的是jstring2str函数是将输入转换为字节数组
观察checkfirst函数

__int64 __fastcall checkfirst(__int64 a1)
{
  signed __int64 v2; // [rsp+0h] [rbp-118h]
  signed __int64 v3; // [rsp+18h] [rbp-100h]
  signed int i; // [rsp+30h] [rbp-E8h]
  char v5; // [rsp+37h] [rbp-E1h]

  for ( i = 1; i < 8; ++i )
  {
    if ( *(_BYTE *)a1 & 1 )
      v3 = *(_QWORD *)(a1 + 16);
    else
      v3 = a1 + 1;
    if ( *(_BYTE *)a1 & 1 )
      v2 = *(_QWORD *)(a1 + 16);
    else
      v2 = a1 + 1;
    if ( *(char *)(v3 + i) <= *(char *)(v2 + i - 1) )// 升序
    {
      v5 = 0;
      return v5 & 1;
    }
  }
  v5 = 1;
  return v5 & 1;
}

关键代码是

 if ( *(char *)(v3 + i) <= *(char *)(v2 + i - 1) )// 升序

由于输入只有16位,由此我们可以大胆猜测*(_BYTE *)a1 & 1的值为0

check first
*flag&1==0 && *(flag+i) > *f(lag+i-1) (1<=i<=7) 即前八位为 1 2 3 4 5 6 7 8 

故可以得到注册码前八位是升序的又因注册码是1~8所以可以得到注册码为
12345678********
进入checkAgain函数

char __fastcall checkAgain(__int64 a1)
{
  char result; // al
  signed __int64 v2; // [rsp+10h] [rbp-170h]
  signed __int64 v3; // [rsp+20h] [rbp-160h]
  signed int l; // [rsp+3Ch] [rbp-144h]
  signed int k; // [rsp+40h] [rbp-140h]
  int j; // [rsp+44h] [rbp-13Ch]
  signed int i; // [rsp+48h] [rbp-138h]
  char v8; // [rsp+4Fh] [rbp-131h]
  int v9; // [rsp+130h] [rbp-50h]
  int v10; // [rsp+134h] [rbp-4Ch]
  int v11; // [rsp+148h] [rbp-38h]
  int v12; // [rsp+14Ch] [rbp-34h]
  int v13[10]; // [rsp+150h] [rbp-30h]
  unsigned __int64 v14; // [rsp+178h] [rbp-8h]

  v14 = __readfsqword(0x28u);
  for ( i = 0; i < 8; ++i )
  {
    if ( *(_BYTE *)a1 & 1 )
      v3 = *(_QWORD *)(a1 + 16);
    else
      v3 = a1 + 1;
    v13[i] = *(char *)(v3 + i) - 49;
  }
  for ( j = 0; j < 8; ++j )
  {
    if ( *(_BYTE *)a1 & 1 )
      v2 = *(_QWORD *)(a1 + 16);
    else
      v2 = a1 + 1;
    *(&v9 + j) = *(char *)(v2 + j + 8) - 49;
  }
  if ( v12 + v9 == 5 )
  {
    if ( v11 + v10 == 12 )
    {
      if ( v9 < v12 )
      {
        for ( k = 1; k < 8; ++k )
        {
          for ( l = 0; l < k; ++l )
          {
            if ( v13[l] == v13[k] )
            {
              v8 = 0;
              goto LABEL_34;
            }
            if ( *(&v9 + l) == *(&v9 + k) )
            {
              v8 = 0;
              goto LABEL_34;
            }
            if ( v13[k] - v13[l] == *(&v9 + k) - *(&v9 + l) )
            {
              v8 = 0;
              goto LABEL_34;
            }
            if ( v13[k] - v13[l] == *(&v9 + l) - *(&v9 + k) )
            {
              v8 = 0;
              goto LABEL_34;
            }
          }
        }
        v8 = 1;
      }
      else
      {
        v8 = 0;
      }
    }
    else
    {
      v8 = 0;
    }
  }
  else
  {
    v8 = 0;
  }
LABEL_34:
  result = v8;
  if ( __readfsqword(0x28u) == v14 )
    result = v8 & 1;
  return result;
}

代码颇长,逐步分析
check主要进行以下功能

check again
i -> range(0,8)
(int)v13[i] = *(flag+i) - 49  
(int)v9[i] = *(flag+i) - 49
v9[7] + v9[0] == 5 && v9[6] + v9[1] == 12 && v9[0] < v9[7]
for k in range(1,8)
    for l in range(0,k)
        v13[l] != v13[k]
        v9[l] != v9[k]
        v13[k] - v13[l] != abs(v9[k] - v9[l])

易得注册码后八位也是不相同的
v9[7] + v9[0] == 5 && v9[6] + v9[1] == 12 && v9[0] < v9[7]结合
v13[k] - v13[l] != abs(v9[k] - v9[l])可以约束求解注册码后八位
最终解得注册码为 1234567836275184

Screenshot_2019-05-09-19-46-51.png

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,104评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,816评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,697评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,836评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,851评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,441评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,992评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,899评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,457评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,529评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,664评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,346评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,025评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,511评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,611评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,081评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,675评论 2 359

推荐阅读更多精彩内容