狗儿的安卓逆向初体验
前言
SWPU的比赛把狗儿整自闭喽~
(后来想了想其实是我对这个比赛的定位搞错啦~我最初以为就是swpu面向他们学校新手的比赛,没想到天河、LinE等等好多大佬也来了。)
MISC不想做,于是先拿RE试了试水,结果一道题没搞出来。四道RE,没有一道题是加壳混淆的,就是最基本的算法逆向,然而还是看不懂。
然后看了看Mobile,先看的Mobile2(此题截止到今晚依旧零解),思路感觉很清晰,但就是不对。然后现学了一下smali和回编译,虽然学会了新知识,但是对解题没有任何帮助。不过借助这些新学的知识把Mobile1做了出来。
下面就写一下mobile1的做题经过。
所以,这篇博文或许应该改名为:android动态调试初探。
参考:
反编译
apktool.jar d -s app1.apk
生成app1的文件夹。
apktool.jar d app1.apk -o app1_smali
生成app1_smali文件夹
不带有-s
时,反编译生成多个smali文件,带有-s
时,会将多个smali文件整合成一个classes.dex
.
java代码
dex2jar classes.dex
将classes.dex转化成.jar文件,并用jd-gui查看。
输入的文本和调用native层的Encrypt()返回的string比较。
修改smali代码
参考:
经过和java代码的对比,我们确认比较字符串的代码在MainActivity$1.smali
.
.class Lcom/example/ndktest2/MainActivity$1;
.super Ljava/lang/Object;
.source "MainActivity.java"
# interfaces
.implements Landroid/view/View$OnClickListener;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/example/ndktest2/MainActivity;->onCreate(Landroid/os/Bundle;)V
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x0
name = null
.end annotation
# instance fields
.field final synthetic this$0:Lcom/example/ndktest2/MainActivity;
.field final synthetic val$password:Landroid/widget/EditText;
# direct methods
.method constructor <init>(Lcom/example/ndktest2/MainActivity;Landroid/widget/EditText;)V
.locals 0
.param p1, "this$0" # Lcom/example/ndktest2/MainActivity;
.line 28
iput-object p1, p0, Lcom/example/ndktest2/MainActivity$1;->this$0:Lcom/example/ndktest2/MainActivity;
iput-object p2, p0, Lcom/example/ndktest2/MainActivity$1;->val$password:Landroid/widget/EditText;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public onClick(Landroid/view/View;)V
.locals 3
.param p1, "view" # Landroid/view/View;
.line 31
iget-object v0, p0, Lcom/example/ndktest2/MainActivity$1;->val$password:Landroid/widget/EditText;
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v0
invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v0
iget-object v1, p0, Lcom/example/ndktest2/MainActivity$1;->this$0:Lcom/example/ndktest2/MainActivity;
invoke-virtual {v1}, Lcom/example/ndktest2/MainActivity;->Encrypt()Ljava/lang/String;
move-result-object v1
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
if-eqz v0, :cond_0
.line 32
iget-object v0, p0, Lcom/example/ndktest2/MainActivity$1;->this$0:Lcom/example/ndktest2/MainActivity;
const/4 v1, 0x1
const-string v2, "\u767b\u5f55\u6210\u529f"
invoke-static {v0, v2, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
.line 33
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
goto :goto_0
.line 36
:cond_0
iget-object v0, p0, Lcom/example/ndktest2/MainActivity$1;->this$0:Lcom/example/ndktest2/MainActivity;
const/4 v1, 0x0
const-string v2, "\u767b\u5f55\u5931\u8d25"
invoke-static {v0, v2, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
.line 39
:goto_0
return-void
.end method
native层中返回的字符串放入寄存器v1.
是否相等的bool量放入寄存器v0.
if-eqz跳转。
失败分支:
Toast是一个悬浮文字控件,第二个参数是输出字符串。
所以我们把第二个参数v2改成存储着native层中返回的字符串的v1,还要把90行对v1的再次赋值改成对v2赋值,然后删掉92行,然后第94行调用的第三个参数改成v2.
这样就可以实现输出v1的字符串。
(把90行对v1的赋值改成对v2赋值,然后删掉92行,然后第94行调用的第三个参数改成v2这一步一是为了防止v1中的字符串被覆写,二是toast的第三个参数不可缺省,且为0或1(0或1存疑))
修改后:
原来是输出登录失败的字符串,现在经过我们的修改后,输出flag.
apktool打包
来到apk文件夹的所在目录
java -jar D:\计算机\CTF\工具\逆向\apktool.jar b app1_smali -o app1_fixed.apk
注意一定要用java -jar
的方式调用apktool.jar
b是build,d是decompile
生成了app1_fixed.apk。但是会安装失败,因为尚未签名。
jarsigner.exe签名
参考:
安装了jdk之后,在jdk/bin下有个jarsigner.exe
,可以用来给apk签名。
powershell来到bin目录下,并将apk放入此目录
jarsigner -verbose -keystore debug.keystore -storepass android -keypass android -signedjar app1_fixed_signed.apk app1_fixed.apk androiddebugkey
-verbose:签名命令标识符。
-keystore:后面跟着的是你签名使用的密钥文件(keystore)的绝对路径。
-signedjar:此后有三个参数:
参数一:签名后生成的apk文件所要存放的路径。
参数二:未签名的apk文件的存放路径。
参数三:你的证书名称,通俗点说就是你keystore文件的别名,就是在你eclipse进行签名打包时的Alias的值。
我这里用的是默认的私钥,debug.keystore 一般位于 ~/.android 目录下。要复制到jdk/bin目录下。
运行
随便输入一些字符,点击登录。
写在后面
这比赛虽然给我整自闭了,但还是藉此学到了一些东西的。
放个彩蛋: