逆向分析某apk

国内的某个姓名软件,有注册版和普通版

image

做下准备工作,用APKTOOL反编译该APK程序,并用dex2jar工具将classes文件转化成jar文件

先来观察AndroidManifest.xml

1
<manifest android:versionCode=”3″ android:versionName=”3.0″ package=”My.XuanAo.Name”
xmlns:android=”http://schemas.android.com/apk/res/android”>
<application android:label=”@string/app_name” android:icon=”@drawable/icon”android:debuggable=”true”>
<activity android:label=”@string/app_name” android:name=”.main”android:screenOrientation=”portrait”>
<intent-filter>
<action android:name=”android.intent.action.MAIN”/>
<category android:name=”android.intent.category.LAUNCHER”/>
</intent-filter>
</activity>
<activity android:name=”.InputDlg” />
<activity android:name=”.SetDlg” />
<activity android:name=”.InputPassDlg” />
<activity android:name=”.InGongSi” />
<activity android:name=”.NameSetDlg” />
<activity android:name=”.WordBookDlg” />
<activity android:name=”.BjxDlg” />
<activity android:name=”.SoftRegDlg” />
<activity android:name=”.SoftHelpDlg” />

核心Activity是My.XuanAo.Name.main,还有这个 有点可疑先记下来,可能是关于注册信息的吧

jd-gui打开jar包,用dex2jar转换的,先看看核心activity,出来了个内部错误
image

算了,再来看看其他SoftRegDlg里面竟然有好多敏感信息的源码

My.XuanAo.Name;
1
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.Editable;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class SoftRegDlg extends Activity
implements View.OnClickListener
{
private Button BtoClose;
private Button BtoOk;
private EditText EdtReg;
private EditText EdtSer;
private boolean m_bFlag;
  privatevoid UiSetTextSize()
  {
   int i = getSharedPreferences("xa_name",0).getInt("uisize", 5);
   if (i == 5)
     return;
   TextView localTextView1 = (TextView)findViewById(2131099742);
   TextView localTextView2 = (TextView)findViewById(2131099744);
   localTextView1.setTextSize(i);
   localTextView2.setTextSize(i);
   this.BtoOk.setTextSize(i);
   this.BtoClose.setTextSize(i);
   this.EdtSer.setTextSize(i);
   this.EdtReg.setTextSize(i);
  }
public void onClick(View paramView)
  {
    if(paramView == this.BtoClose)
    {
     setResult(0);
     finish();
    }
   if (paramView == this.BtoOk)
    {
     if (this.m_bFlag)
     {
       setResult(0);
       finish();
     }
    }
   else
     return;
   String str = this.EdtReg.getText().toString().trim();
   if (str.length() == 15)
     for (int i = 0; ; i++)
     {
       if (i >= 15)
       {
         main.m_chkSoft.Fregcode = str;
         if ((main.m_chkSoft.ChkNumA()) && (main.m_chkSoft.ChkNumB())&& (main.m_chkSoft.ChkNumC()))
         {
           main.m_chkSoft.WriteRegCode(str);
           this.m_bFlag = true;
         }
         Intent localIntent = getIntent();
         localIntent.putExtra("reg", this.m_bFlag);
         setResult(104, localIntent);
          finish();
         return;
       }
       if ((str.charAt(i) < '0') || (str.charAt(i) > '9'))
       {
         Toast.makeText(this, "请输入数字。", 1).show();
         return;
       }
     }
   Toast.makeText(this, "请输入注册号。", 1).show();
  }
public void onCreate(Bundle paramBundle)
  {
   super.onCreate(paramBundle);
   setContentView(2130903048);
   this.m_bFlag = getIntent().getBooleanExtra("reg", false);
   this.BtoOk = ((Button)findViewById(2131099746));
   this.BtoClose = ((Button)findViewById(2131099747));
   this.EdtSer = ((EditText)findViewById(2131099743));
   this.EdtReg = ((EditText)findViewById(2131099745));
   this.BtoOk.setOnClickListener(this);
   this.BtoClose.setOnClickListener(this);
   if (this.m_bFlag)
    {
     this.EdtSer.setText("已注册");
     this.EdtReg.setText("已注册");
    }
   while (true)
    {
     UiSetTextSize();
     return;
     this.EdtSer.setText(main.m_chkSoft.Fsoftsn);
     this.EdtReg.setText("");
    }
  }
}

除了核心activity都逆向出来了源码太危险了,差不多都可以仿照写一个了,上面主要有个判断if((main.m_chkSoft.ChkNumA()) && (main.m_chkSoft.ChkNumB()) &&(main.m_chkSoft.ChkNumC())),ChkNumA(),ChkNumB()和ChkNumC()条件都满足是就为已经注册,这三个应该是主程序的算法,随便贴一个ChkNumA()看看

boolean ChkNumA()
1
{
 long l1 = 0L;
 char[] arrayOfChar = new char[6];
 if ((this.Fregcode.length() != 15) || (this.Fsoftsn.length() != 12))
   return false;
 long l2 = 10000L;
 int i = 1;
 do
  {
   l1 += l2 * ('￐' + this.Fregcode.charAt(i - 1));
   i++;
   l2 /= 10L;
  }
 while (l2 > 0L);
 String str = String.valueOf((1265L + (l1 ^ SnCal(1265L))) / 3L -1265L).trim();
 long l3 = str.length();
 str.getChars(0, (int)l3, arrayOfChar, 0);
 long l4;
 int k;
 int m;
 if (l3 < 4L)
  {
   l4 = 4L - l3;
   k = (int)(l3 - 1L);
   if (k >= 0)
     break label179;
   m = 0;
   label160: if (m < (int)l4)
     break label198;
  }
 for (int j = 1; ; j++)
  {
   if (j > 4)
   {
     return true;
     label179: arrayOfChar[((int)(l4 + k))] = arrayOfChar[k];
     k--;
     break;
     label198: arrayOfChar[m] = '0';
     m++;
     break label160;
   }
   if (arrayOfChar[(j - 1)] != this.Fsoftsn.charAt(j - 1))
     return false;
  }
}

主要看他有一个返回值是要和另外两个方法比较的,如果让他们返回的值相同那么就可能达到注册了的效果,在这个CSoftReg类里面还看到了文件操作方法
取出信息比较
image
apktool打开定位到ChkNumA()

virtual methods
1
.method public ChkNumA()Z
    .locals 14
    .prologue
    .line 256
    const-wide/16 v0, 0x4f1
    .line 257
    .local v0, DW1:J
    const-wide/16 v9, 0x0
    .line 258
    .local v9, tol:J
    const/4 v11, 0x6
    new-array v2, v11, [C
    .line 260
    .local v2, cnum:[C
    const-string v4, ""
    .line 262
    .local v4, stmp:Ljava/lang/String;
    iget-object v11, p0, LMy/XuanAo/Name/CSoftReg;->Fregcode:Ljava/lang/String;
    invoke-virtual {v11}, Ljava/lang/String;->length()I
    move-result v11
    const/16 v12, 0xf
    if-ne v11, v12, :cond_0
    iget-object v11, p0, LMy/XuanAo/Name/CSoftReg;->Fsoftsn:Ljava/lang/String;
    invoke-virtual {v11}, Ljava/lang/String;->length()I
    move-result v11
    const/16 v12, 0xc
    if-eq v11, v12, :cond_1
    :cond_0
    const/4 v11, 0x0   返回为假
    .line 288
    :goto_0
    return v11 这句很关键代表ChkNumA()的返回内容
    .line 263
    :cond_1
    const-wide/16 v5, 0x2710
    .local v5, t1:J
    const/4 v3, 0x1

return v11 这句很关键代表ChkNumA()的返回内容,可以在这句前定义条赋值指令,让v11返回值为真,然后其他两个函数的返回值也一样

比如const/4 v11, 0x1
ChkNumB()也类似

1
method public ChkNumB()Z
    .locals 14
    .prologue
    .line 293
    const-wide/16 v0, 0x805
    .line 294
    .local v0, DW1:J
    const-wide/16 v9, 0x0
    .line 295
    .local v9, tol:J
    const/4 v11, 0x6
    new-array v2, v11, [C
    .line 297
    .local v2, cnum:[C
    const-string v4, ""
    .line 299
    .local v4, stmp:Ljava/lang/String;
    iget-object v11, p0, LMy/XuanAo/Name/CSoftReg;->Fregcode:Ljava/lang/String;
    invoke-virtual {v11}, Ljava/lang/String;->length()I
    move-result v11
    const/16 v12, 0xf
    if-ne v11, v12, :cond_0
    iget-object v11, p0, LMy/XuanAo/Name/CSoftReg;->Fsoftsn:Ljava/lang/String;
    invoke-virtual {v11}, Ljava/lang/String;->length()I
    move-result v11
    const/16 v12, 0xc
    if-eq v11, v12, :cond_1
    :cond_0
    const/4 v11, 0x0
    .line 326
    :goto_0
    return v11  就是这句,返回值
    .line 300
    :cond_1
    const-wide/16 v5, 0x2710
    .local v5, t1:J
    const/4 v3, 0x6

return v11 就是这句,返回值,同样在前面定义相同的赋值句使返回值为真
const/4 v11, 0x1
ChkNumC()也是这样然后保存编译就得到了注册版,image
源软件附上http://pan.baidu.com/s/1mgmL7VM
原本想探索下android加壳方案,看了下csdn上的博客,感觉自己功力不够然后期末考试又多实在是好蛋疼钓丝还是继续潜水吧