初见

附件为一个apk,先到模拟器中运行一下。

必须选择CPU为ARM的模拟器,因为app里面的native库只提供了ARM指令集的版本,没有提供x86指令集的版本:

模拟器启动后,将apk拖到模拟器中进行安装,安装好后,列表中app的图标是一个骚年:

运行app,又见一个骚年:

除了一个按钮啥也没有,点击这个按钮,弹出一个两按钮的对话框:

点击“不玩了”,app直接退出。

点击“注册”,进入新的界面。在新界面中,可以输入一串字符串,并有一个注册按钮。随便输入一个串,点击注册,弹框显示“您的注册码已保存”:

弹框后,进程立即退出。从行为上暂时看不出这个注册码的作用,反编译看看代码。

MainActivity分析

使用jadx打开apk,先看一下MainActivity的代码,在onCreate函数内可以找到,“自由定义分享”按钮的响应函数:

this.btn1.setOnClickListener(new View.OnClickListener() {      public void onClick(View v) {MyApp myApp2 = (MyApp) MainActivity.this.getApplication();if (MyApp.m == 0) {MainActivity.this.doRegister();return;}((MyApp) MainActivity.this.getApplication()).work();Toast.makeText(MainActivity.this.getApplicationContext(), MainActivity.workString, 0).show();}
});

核心就是,MyApp.m为空时,调用doRegister()。随后调用work()。

先看看doRegister()函数:

    public void doRegister() {new AlertDialog.Builder(this).setTitle("注册").setMessage("Flag就在前方!").setPositiveButton("注册", new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {Intent intent = new Intent();intent.setComponent(new ComponentName(BuildConfig.APPLICATION_ID, "com.gdufs.xman.RegActivity"));MainActivity.this.startActivity(intent);MainActivity.this.finish();}}).setNegativeButton("不玩了", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) {Process.killProcess(Process.myPid());}}).show();}

可见,这个doRegister()函数就是弹出下图对话框并处理按钮点击:

点击“不玩了”,直接killProcess。

点击“注册”,以类"com.gdufs.xman.RegActivity"创建新Activity并启动。

总结来看就是:

如果MyApp.m为空,创建RegActivity进行注册,使得MyApp.m不为空。然后调用work()。

如果MyApp.m不为空,直接调用work()。

而这个work是个native函数:

public native void work();

RegActivity

RegActivity对应如下界面:

重点在“注册”按钮的响应函数:

public void onClick(View v) {String sn = RegActivity.this.edit_sn.getText().toString().trim();if (sn == null || sn.length() == 0) {Toast.makeText(RegActivity.this, "您的输入为空", 0).show();return;}((MyApp) RegActivity.this.getApplication()).saveSN(sn);new AlertDialog.Builder(RegActivity.this).setTitle("回复").setMessage("您的注册码已保存").setPositiveButton("好吧", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) {Process.killProcess(Process.myPid());}}).show();
}

可见,点击“注册”按钮后:

  1. 调用saveSN()函数进行注册
  2. 弹框提示“您的注册码已保存”,如上图
  3. killProcess

到这里,已经分析出来的逻辑是:

如果MyApp.m为空,调用saveSN()进行注册,然后调用work()。

如果MyApp.m不为空,直接调用work()。

这个saveSN()也是native函数:

public native void saveSN(String str);

下面我们就分析分析这个两个native函数。

native库分析

将apk后缀名改为zip并解压,在解压后的lib目录下能得到native库文件:libmyjni.so。

用IDA加载libmyjni.so。

但在导出函数中没有找到work函数和saveSN函数。但能看到导出了JNI_OnLoad函数,这让人联想起JNI函数的动态注册方式:

  1. 利用结构体 JNINativeMethod 数组记录 java 方法与 JNI 函数的对应关系;

  2. 实现 JNI_OnLoad 方法,在加载动态库后,执行动态注册;

  3. 调用 FindClass 方法,获取 java 对象;

  4. 调用 RegisterNatives 方法,传入 java 对象,以及 JNINativeMethod 数组,以及注册数目完成注册;

这和该题的JNI_OnLoad函数过程一致:

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{if ( !(*vm)->GetEnv(vm, (void **)&g_env, 65542) ){j___android_log_print(2, "com.gdufs.xman", "JNI_OnLoad()");native_class = (*(int (__fastcall **)(int, const char *))(*(_DWORD *)g_env + 24))(g_env, "com/gdufs/xman/MyApp");if ( !(*(int (__fastcall **)(int, int, char **, int))(*(_DWORD *)g_env + 860))(g_env, native_class, off_5004, 3) ){j___android_log_print(2, "com.gdufs.xman", "RegisterNatives() --> nativeMethod() ok");return 65542;}j___android_log_print(6, "com.gdufs.xman", "RegisterNatives() --> nativeMethod() failed");}return -1;
}

可见,off_5004就是java函数和JNI函数的对应关系,据此得到对应关系为:

  • InitSN----n1
  • SaveSN----n2
  • Work----n3

下面分析native函数。

SaveSN

核心反编译代码为:

int __fastcall n2(int a1, int a2, int a3)
{v5 = j_fopen("/sdcard/reg.dat", "w+");strcpy(v13, "W3_arE_whO_we_ARE");v7 = input_string;v8 = v7;v12 = j_strlen(v7);v9 = 2016;while ( 1 ){v10 = v8 - v7;if ( v8 - v7 >= v12 )break;if ( v10 % 3 == 1 ){v9 = (v9 + 5) % 16;v11 = v13[v9 + 1];}else if ( v10 % 3 == 2 ){v9 = (v9 + 7) % 15;v11 = v13[v9 + 2];}else{v9 = (v9 + 3) % 13;v11 = v13[v9 + 3];}*v8++ ^= v11;}j_fputs(v7, v5);return j_fclose(v5);
}

这里的伪代码是我简化之后的,方便理解。这个里核心逻辑为:

  1. 在循环中,依据"W3_arE_whO_we_ARE"对输入字符串进行变形
  2. 将变形后的字符串存入文件"/sdcard/reg.dat"

InitSN

核心反编译代码为:

int __fastcall n1(int a1)
{v2 = j_fopen("/sdcard/reg.dat", "r+");j_fread(v6, v5, 1, v2);if ( !j_strcmp(v6, "EoPAoY62@ElRD") ){v8 = a1;v9 = 1;}else{v8 = a1;v9 = 0;}return j_fclose(v3);
}

这里的伪代码也是我简化过得,核心功能逻辑为:

  1. 读"/sdcard/reg.dat"文件的内容
  2. 比较内容是不是"EoPAoY62@ElRD"

到这里就清楚了,这道题就是要我们的输入字符串,在SaveSN中经过变形后为"EoPAoY62@ElRD"。

解题

SaveSN中对输入字符串进行变形的逻辑也很简单:

  1. 取输入字符串里的每个字符a
  2. 根据该字符在输入字符串里的下标,计算出一个值i
  3. 取"W3_arE_whO_we_ARE"中下标为i的字符b
  4. 计算a异或b的值,写入文件

根据变形过程,使用python实现解密代码:

seedstr = bytes('W3_arE_whO_we_ARE','utf-8')
seed = 2016;
result = bytes('EoPAoY62@ElRD','utf-8')
for i in range(13):if(i % 3 == 1):seed = (seed + 5) % 16tmp = seedstr[seed + 1]tmp = tmp ^ result[i]print(chr(tmp), end = '')elif(i % 3 == 2):seed = (seed + 7) % 15tmp = seedstr[seed + 2]tmp = tmp ^ result[i]print(chr(tmp), end = '')else:seed = (seed + 3) % 13tmp = seedstr[seed + 3]tmp = tmp ^ result[i]print(chr(tmp), end = '')

得到字符串:201608Am!2333。

输入该字符串进行注册,之后再次打开app,点击“自由正义分享”,提示:

所以flag为:xman{201608Am!2333}

———————————————————————————————————————————

欢迎关注我的微博:大雄_RE。专注软件逆向,分享最新的好文章、好工具,追踪行业大佬的研究成果。

XCTF_MOBILE11_黑客精神相关推荐

  1. 陆奇:“黑客精神”过时了吗?答案是永远不会

    本文作者陆奇,奇绩创坛创始人兼 CEO.文章内容来源<黑客与画家(10万册纪念版)>推荐序. <黑客与画家>出版距离现在已经 18 年了,这十多年互联网每天都有新变化,我们有幸 ...

  2. 攻防世界 黑客精神unidbg破解

    攻防世界 黑客精神unidbg破解 一.Jadx分析 首先用jadx打开apk文件,查看MainActivity可以发现,页面判断了MyApp.m这个类变量的值,并调用类work()这个函数,且当类变 ...

  3. 刚子扯谈:我对黑客精神的一些认知

    文:刚子 谈谈个人对黑客的理解吧,方便大家对"黑客"有所认知. 黑客(英文:Hacker,或称骇客),通常是指对计算机科学.编程和设计方面具高度理解的人. 在信息安全里," ...

  4. 刚子扯谈:黑客文化 黑客精神

    文/刚子 2013年7月27日 由于最近几日的安全漏洞如苹果沦陷.淘宝沦陷.网易沦陷.乐蜂.百合.京东--而又由于一个叫"Struts 2"的安全漏洞让众多知名网站陷入安全危机,让 ...

  5. 黑客精神 与 清心寡欲

    [此处不再更新]原文地址:http://wargrey.yo2.cn/2009/06/09/31218/ 外传一: 和任何一个大学新生一样,我也对大学的任何事物感到新鲜.尤其是新同学,我们都是计算机专 ...

  6. 黑客精神是什么?小黑QQ1440580来告诉你们:

    "黑客:是帮助程序源和开发创作者们发现错误和可利用的逻辑性环节然后告诉程序源和开发者来改正促进网络发展,如今社会网络的原地踏步大多人而不是黑客利用漏洞来获取财物,这些利用漏洞的人只能称之为黑 ...

  7. 【黑客浅析】像黑客一样思考

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 作者:由云鼎实验室发表在云+社区 网络安全里经常说的一句话是未知攻焉知防,基本所有的安全人员也是一名黑客,在黑客攻击愈发普遍的今天,如何更好 ...

  8. 黑客之王!韩国神童登顶黑客界的“极限挑战”

    现场不允许拍照,所有的竞赛题目和技术分享都不能泄露.这就是黑客大师赛 WCTF 散发出的的"黑客气质". 所谓 CTF,就是黑客界流行的一种竞赛.大致来说就是各大战队依靠自己的独门 ...

  9. 世界上最大的黑客 Party,有关“DEFCON”的十个冷知识

    如果你对世界上的某些事情并不满意,并且决定用一切可能的方式来达成你的目标.恭喜你,你正在成为一名黑客. 全世界那些敢于对不可能竖中指的黑客,每年都会聚集在罪恶之都拉斯维加斯,参加一个盛大 Party ...

最新文章

  1. 安装acdsee 3.1后出错
  2. 《系统集成项目管理工程师》必背100个知识点-98大数据的特点
  3. ubuntu 14.04 编译android4.0 出现gcc-version.sh: line 11: cc: command not found错误解决方法
  4. linux c之main(int argc, char *argv[], char *envp[])参数意义
  5. urllib2库的基本使用
  6. java文件日志功能_JAVA文件下载功能问题解决日志
  7. 本地gradle使用
  8. android美颜功能吗,Android美颜sdk接入之前需要知道这些知识吗
  9. js调用打印机直接打印_打印机如何打印二维码
  10. spring中context:property-placeholder
  11. 通信原理ami码c语言实现,通信原理AMI码型变换实验
  12. 阿里巴巴的业务范畴/文化和价值观
  13. 公司基础网络架构及实现
  14. .vm后缀的文件是什么?
  15. GateWay网关访问服务出现503的问题解决
  16. 【Windows】多显示器拔出HDMI接口线后应用界面丢失问题
  17. 小白初写Spring核心容器功能
  18. 外媒:阿里巴巴选择中金和瑞信牵头安排香港股份发行
  19. 一个屌丝程序员的青春(一三七)
  20. 经典永恒--21guns

热门文章

  1. html 空间扭曲效果,HTML5 Canvas点阵空间塌缩交互动画
  2. 微信分享笔记(第二版)
  3. cad开发 php,什么叫cad软件
  4. SSH、SSM三种框架及表示层、业务层和持久层的理解
  5. 单调递增且值域非负的函数
  6. 助力交通出行,基于目标检测模型实现路面裂痕缺陷智能识别
  7. 二本师大计算机排名,全国师范类大学排名 二本师范大学有哪些
  8. Yaesu FT1XDR写频
  9. CANOpen,关于 DS402 电机驱动器的状态切换
  10. 浙江:2010年文理科第二批首轮平行投档分数线