样例1 (2)

样例1 (2)
一个安卓练手例题1:
模拟器运行结果——》

样例1 (2)勇杰尼龟打开,并且打开安卓配置文件如下图
样例1 (2)
程序入口界面找到 后直接进去看
样例1 (2)
找到 了点击事件监听器
逻辑差不多为,输入不为空则调用NI的greyolf方法,以此来判断输入是否正确。
接下来分析so层
打开ida,我们输出函数界面,ctrl+f 搜索java_ 没有结果,那基本可以肯定这个apk是采用的JNIload 动态注册
我们在函数输出界面搜索JNIload
样例1 (2)
进入该函数
样例1 (2)
样例1 (2)
样例1 (2)

获取 TracerPid 的值,这也是一个反调试逻辑,我们只需要 在这里nop掉这个调用代码处就行了。
样例1 (2)
完整的汇编代码
这里我们重点关注这串代码
样例1 (2)
这是一个关键的注册函数,而注册函数有4个参数分别是ENV ,CLASS ,注册方法结构体,需要注册函数数量。
经分析得知在这里
R0 = ENV 从getenv 获取出来的

R1 =CLASS 有个findclass

R2 =方法体 ADDS R2, R2, R0 ; dword_58058

R4 = 注册方法的个数
我们由此进入逻辑实现位置,转化成伪代码看看逻辑。
int (*sub_146A4())()
{
int (*result)(); // r0
dword_58058 = j_wolf_de(“6C7A5CA7B2DC4B9C”);
dword_5805C = j_wolf_de(“234458B0A1C1489300D2572AA3D004E057970FFF6FC1318CF5F6135E6D062813D2642446BD540E79927E12CD4199”);
result = bc; dword_58060 = bc;
return result;
}
进入其中的bc方法
int __fastcall bc(JNIEnv *a1, jclass a2, int a3, String str)
{
String v4; // r6
int v5; // r4
JNIEnv *v6; // r5
int v7; // r0
int v8; // r1
int v10; // r0

v4 = str;
v5 = a3;
v6 = a1;
v7 = j_jstringTostring(a1, str);///第一个参数 ,env 第二个参数是输入的密码。

int v4; // r0
std::__node_alloc *v5; // r5
std::__node_alloc *v6; // r6
unsigned int v7; // r2
signed int v8; // r4
int v9; // r0
int result; // r0
char v11; // [sp+8h] [bp-8h]
char v12; // [sp+Ch] [bp-4h]
int v13; // [sp+10h] [bp+0h]
int v14; // [sp+20h] [bp+10h]
std::__node_alloc *v15; // [sp+24h] [bp+14h]
int v16; // [sp+28h] [bp+18h]
int v17; // [sp+38h] [bp+28h]
std::__node_alloc *v18; // [sp+3Ch] [bp+2Ch]
int v19; // [sp+40h] [bp+30h]

v3 = a3;
if ( j_dh(a1, a2) )
{
v4 = j_wolf_de(“636D55B2AA8609CB”);
sub_15184(&v16, v4, &v12);///整个程序就走到了这个位置! 这里返回出来的就是正确密码hello5.1
sub_15184(&v13, v3, &v11);
v5 = v18;
v6 = v15;
v7 = v17 - v18;
v8 = 0;
if ( v17 - v18 == v14 - v15 )
{
v8 = 1;
if ( j_memcmp(v18, v15) )
v8 = 0;
}
if ( v6 != &v13 && v6 )
{
j_std::__node_alloc::deallocate(v6, (v13 - v6), v7);
v5 = v18;
}
if ( v5 != &v16 && v5 )
j_std::__node_alloc::deallocate(v5, (v16 - v5), v7);
}
else
{
v9 = j_getpid();
j_kill(v9, 9);
v8 = 0;
}
result = _stack_chk_guard - v19;
if ( _stack_chk_guard == v19 )
result = v8;
return result;
}
最后跑完整个程序,最终密码是hello5.1

小结:这个题目困扰了很久,就算是看了wp还是很不熟练,经验不足,还是要找更多代码看看。

例题2:一个随便找的例题样例1 (2)

样例1 (2)由此我们知道了入口com.yaotong.crackme.MainActivity
并且这里还要加android:bebuggable ="true"以便到时候ida进行调试。
样例1 (2)

进入主类,发现其定义一个button,并且点击是 调用检测函数,并且securityCheck呗注册进了so文件中,我们使用ida进行调试,查看该函数。
F5后如图
样例1 (2)
但是在调试代码是总是弹出,看wp知道是有反调试的代码在JNI_Onload中,反调试的 手短很多种,很多情况都会在init_array或者JNI_Onload开启线程检测或者端口之类的。
我们回到正常流程
根据之前提到的我们先在
AndroidManifest.xml添加android:debuggable=“true”,打包APK:apktool b ali -o ll.apk,使用android killer进行签名,将APK安装到模拟器上。
想要动态调试so文件,需要将IDA pro里面的android_server push 到手机 /data/local/tmp文件夹下,并赋予777权限
连接上ida后,linker加载进来之后 ctrl+s搜索目标so
样例1 (2)
将断点下到Jni_onload,进去单步调试,发现到BLX R7之后程序会闪退。
我们nop掉这段指令。
随后我们打开SecurityCheck函数,下断点,F9在手机上随便输入密码:crackSample,开始单步调试
随后找到这一段样例1 (2)
这就是正确的密码了
aiyou,bucuoo
密码输入回去查看结果
样例1 (2)

3.打开这个“CTF_100”,界面显示如下:
样例1 (2)

点击按钮“爬到了,看FLAG”,但这个按钮点击了没有反应,点击“爬一层楼”按钮,“已爬楼层”数值会加1。我们是不可能就这么点到196608层的。
使用杰尼龟来看看
样例1 (2)
样例1 (2)
这里这个setClickable就是将这个按钮设置为不可点击的状态,这个可能与之前的按钮没反应有关系。
这里就试试把这个false改成true
这里很容易就找到了这个 地方的smali代码
改成1就好了。样例1 (2)
样例1 (2)
这个题应该就是道签到题,没啥好说的。