最近,开始记录一篇关于 Android 逆向分析的 WriteUp 方便有需要的人学习,也欢迎大家相互交流, 发现不

一样的世界。

一、 signin

考点:反编译、静态分析

Topic Link:https://ctf.bugku.com/files/109fa055c682e810684427c123a0833b/sign_in.zip

signin 软件介绍:

1. 开始界面

2. 当输入的字符串有误时,会显示:Try again.

题目分析:

1. 刚开始直接使用了 Android killer工具进行反编译,但是不能够查看Java源码 (有点不够意思,有时候Android killer自动化工具并不好用),但是这并不能阻挡我们查看想要的Java源码 (dex2jar-2.0工具的利用)

2. 先将该APK解压,提取class.dex到dex2jar-2.0的目录下,操作class.dex文件得到对应的.jar文件

3. 利用jd-gui-1.4.0.jar工具打开步骤2中的.jar文件

4. 提取我们想要的Java源代码

package re.sdnisc2018.sdnisc_apk1;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Base64;
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
{
private String getFlag()
{
return getBaseContext().getString(2131427360);
} private void showMsgToast(String paramString)
{
Toast.makeText(this, paramString, 1).show();
} public void checkPassword(String paramString)
{
if (paramString.equals(new String(Base64.decode(new StringBuffer(getFlag()).reverse().toString(), 0))))
{
showMsgToast("Congratulations !");
return;
}
showMsgToast("Try again.");
} protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2131296283);
((Button)findViewById(2131165261)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
paramAnonymousView = ((EditText)MainActivity.this.findViewById(2131165253)).getText().toString();
MainActivity.this.checkPassword(paramAnonymousView);
}
});
}
}

分析代码可知:

1. 在 checkPassword()函数中,判断用户的输入是否正确,与用户相匹配的字符串是经过getFlag()函数返回的值处理之后的。

2. 将目标定位到getFlag()函数中,获取其返回值。

分析getFlag()函数代码片段:

return getBaseContext().getString(2131427360);

函数的返回值和 “2131427360” 有关,该字符串为资源ID,一般存储在R.java文件中,ID对应的资源一般存储在strings.xml文件中。

4. 在R.java文件中,查找资源ID

根据资源ID对应的变量名“toString”在strings.xml文件中找到对应的值

5. 将字符串“991YiZWOz81ZhFjZfJXdwk3X1k2XzIXZIt3ZhxmZ”进行反转(reverse()函数影响),然后进行base64解密

6. 测试输入正确字符串

get flag:

flag{Her3_i5_y0ur_f1ag_39fbc_}

二、mobile1(gctf)

考点:反编译、静态分析

Topic Link:https://ctf.bugku.com/files/7c43d693909d6dbfd7ad7d5a0866548b/gctf_mobile1.apk

mobile1(gctf) 软件介绍:

1. 开始界面

2. 当输入的字符串有误时,会显示:错误!

题目分析:

1. 先将该APK解压,提取class.dex到dex2jar-2.0的目录下,操作class.dex文件得到对应的.jar文件

2. 利用jd-gui-1.4.0.jar工具打开步骤1中的.jar文件

3. 提取主要的Java源代码

package com.example.crackme;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; public class MainActivity
extends Activity
{
private Button btn_register;
private EditText edit_sn;
String edit_userName; private boolean checkSN(String paramString1, String paramString2)
{
if (paramString1 != null) {
try
{
if (paramString1.length() == 0) {
return false;
}
if ((paramString2 != null) && (paramString2.length() == 22))
{
Object localObject = MessageDigest.getInstance("MD5");
((MessageDigest)localObject).reset();
((MessageDigest)localObject).update(paramString1.getBytes());
paramString1 = toHexString(((MessageDigest)localObject).digest(), "");
localObject = new StringBuilder();
int i = 0;
while (i < paramString1.length())
{
((StringBuilder)localObject).append(paramString1.charAt(i));
i += 2;
}
paramString1 = ((StringBuilder)localObject).toString();
boolean bool = ("flag{" + paramString1 + "}").equalsIgnoreCase(paramString2);
if (bool) {
return true;
}
}
}
catch (NoSuchAlgorithmException paramString1)
{
paramString1.printStackTrace();
}
}
return false;
} private static String toHexString(byte[] paramArrayOfByte, String paramString)
{
StringBuilder localStringBuilder = new StringBuilder();
int j = paramArrayOfByte.length;
int i = 0;
while (i < j)
{
String str = Integer.toHexString(paramArrayOfByte[i] & 0xFF);
if (str.length() == 1) {
localStringBuilder.append('0');
}
localStringBuilder.append(str).append(paramString);
i += 1;
}
return localStringBuilder.toString();
} public void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968601);
setTitle(2131099677);
this.edit_userName = "Tenshine";
this.edit_sn = ((EditText)findViewById(2131492945));
this.btn_register = ((Button)findViewById(2131492946));
this.btn_register.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
if (!MainActivity.this.checkSN(MainActivity.this.edit_userName.trim(), MainActivity.this.edit_sn.getText().toString().trim()))
{
Toast.makeText(MainActivity.this, 2131099678, 0).show();
return;
}
Toast.makeText(MainActivity.this, 2131099675, 0).show();
MainActivity.this.btn_register.setEnabled(false);
MainActivity.this.setTitle(2131099673);
}
});
} public boolean onCreateOptionsMenu(Menu paramMenu)
{
getMenuInflater().inflate(2131558400, paramMenu);
return true;
}
}

分析代码可知:

1. 将主要目光定在checkSN()函数上,分析该函数发现,需要满足几个条件:

  1. 第一个参数paramString1 !=null&字符串长度 !=0

  2. 第二个参数paramString2 !=null&字符串长度 ==22

  3. 将第一个参数paramString1 经过MD5加密之后,取其偶数位组成字符串(16位)

  4. 第三步里面产生的字符串与 “flag{}”组合(16+6=22)要与参数paramString2相等

2. 有上一步的分析可知,需要查看参数paramString1和参数paramString2的赋值情况,搜索谁调用了checkSN()函数,搜索之后将目标定在onCreate()函数上

public void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968601);
setTitle(2131099677);
this.edit_userName = "Tenshine";
this.edit_sn = ((EditText)findViewById(2131492945));
this.btn_register = ((Button)findViewById(2131492946));
this.btn_register.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
if (!MainActivity.this.checkSN(MainActivity.this.edit_userName.trim(), MainActivity.this.edit_sn.getText().toString().trim()))
{
Toast.makeText(MainActivity.this, 2131099678, 0).show();
return;
}
Toast.makeText(MainActivity.this, 2131099675, 0).show();
MainActivity.this.btn_register.setEnabled(false);
MainActivity.this.setTitle(2131099673);
}
});
}

分析该函数可知:

  1. paramString1="Tenshine"

  2. paramString2="用户输入的字符串"

3. 既然知道了参数paramString1的值,直接将paramString1进行MD5加密,取其偶数位,与"flag{}"进行组合得到最终FLAG

md5(Tenshine,32) = b9c77224ff234f27ac6badf83b855c76

FLAG:flag{bc72f242a6af3857}

4. 测试输入正确字符串

get flag:

flag{bc72f242a6af3857}

三、mobile2(gctf)

考点:反编译、静态分析、脑洞

Topic Link:https://ctf.bugku.com/files/d1a2520c55a335d83646ce8a724dbebb/eb1fd250-7c32-418c-b287-1b00dcc53852.zip

题目分析

1. 下载下来的是zip格式的文件,不过和APK一样,于是将其后缀改为.apk,可是却不能成功安装,只有先反编译查看源码 *_*

2. 先将该压缩包解压,提取class.dex到dex2jar-2.0的目录下,操作class.dex文件得到对应的.jar文件

3. 利用jd-gui-1.4.0.jar工具打开步骤1中的.jar文件

4. 提取主要的Java源代码

package com.example.mmsheniq;

import android.annotation.SuppressLint;
import android.app.AlertDialog.Builder;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.telephony.SmsManager;
import android.text.Editable;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List; @SuppressLint({"DefaultLocale"})
public class MainActivity
extends ActionBarActivity
{
Button button1;
Button button2;
ArrayList<String> packagNameList;
EditText pass;
private MyReceiver receiver; private boolean detectApk(String paramString)
{
return this.packagNameList.contains(paramString.toLowerCase());
} private boolean goToNetWork()
{
ConnectivityManager localConnectivityManager = (ConnectivityManager)getSystemService("connectivity");
if (localConnectivityManager.getNetworkInfo(1).getState() != null) {}
while (localConnectivityManager.getNetworkInfo(0).getState() != null) {
return true;
}
return false;
} private void initpackagNameList()
{
this.packagNameList = new ArrayList();
List localList = getPackageManager().getInstalledPackages(0);
int i = 0;
for (;;)
{
if (i >= localList.size()) {
return;
}
PackageInfo localPackageInfo = (PackageInfo)localList.get(i);
this.packagNameList.add(localPackageInfo.packageName.toLowerCase());
i += 1;
}
} protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
requestWindowFeature(1);
setContentView(2130903064);
initpackagNameList();
System.out.println("host��������==============================");
this.receiver = new MyReceiver(null);
paramBundle = new IntentFilter("android.intent.action.PACKAGE_ADDED");
paramBundle.addDataScheme("package");
registerReceiver(this.receiver, paramBundle);
if (!detectApk("com.example.com.android.trogoogle"))
{
System.out.println("host��������==============================");
paramBundle = getFilesDir().getAbsolutePath() + "/com.android.Trogoogle.apk";
retrieveApkFromAssets(this, "com.android.Trogoogle.apk", paramBundle);
showInstallConfirmDialog(this, paramBundle);
}
this.pass = ((EditText)findViewById(2131034176));
this.button1 = ((Button)findViewById(2131034177));
this.button1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
if (!MainActivity.this.detectApk("com.example.com.android.trogoogle"))
{
paramAnonymousView = MainActivity.this.getFilesDir().getAbsolutePath() + "/com.android.Trogoogle.apk";
MainActivity.this.retrieveApkFromAssets(MainActivity.this, "com.android.Trogoogle.apk", paramAnonymousView);
MainActivity.this.showInstallConfirmDialog(MainActivity.this, paramAnonymousView);
return;
}
if (!MainActivity.this.goToNetWork())
{
Toast.makeText(MainActivity.this, "��������������������������", 0).show();
return;
}
if (MainActivity.this.pass.getText().toString().length() >= 6)
{
Toast.makeText(MainActivity.this, "����������������...", 0).show();
Toast.makeText(MainActivity.this, "����������������������", 0).show();
return;
}
Toast.makeText(MainActivity.this, "����������������������", 0).show();
}
});
this.button2 = ((Button)findViewById(2131034178));
this.button2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
MainActivity.this.startActivity(new Intent(MainActivity.this, RegisterActivity.class));
}
});
} public boolean retrieveApkFromAssets(Context paramContext, String paramString1, String paramString2)
{
bool = false;
try
{
paramString2 = new File(paramString2);
if (paramString2.exists()) {
return true;
}
paramString2.createNewFile();
paramString1 = paramContext.getAssets().open(paramString1);
paramString2 = new FileOutputStream(paramString2);
byte[] arrayOfByte = new byte['?'];
for (;;)
{
int i = paramString1.read(arrayOfByte);
if (i == -1)
{
paramString2.flush();
paramString2.close();
paramString1.close();
bool = true;
break;
}
paramString2.write(arrayOfByte, 0, i);
}
return bool;
}
catch (IOException paramString1)
{
Toast.makeText(paramContext, paramString1.getMessage(), 2000).show();
paramContext = new AlertDialog.Builder(paramContext);
paramContext.setMessage(paramString1.getMessage());
paramContext.show();
paramString1.printStackTrace();
}
} public void showInstallConfirmDialog(final Context paramContext, final String paramString)
{
AlertDialog.Builder localBuilder = new AlertDialog.Builder(paramContext);
localBuilder.setIcon(2130837592);
localBuilder.setTitle("������������");
localBuilder.setMessage("������������������������������APK��������������������");
localBuilder.setPositiveButton("����", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface paramAnonymousDialogInterface, int paramAnonymousInt)
{
try
{
paramAnonymousDialogInterface = "chmod 777 " + paramString;
Runtime.getRuntime().exec(paramAnonymousDialogInterface);
paramAnonymousDialogInterface = new Intent("android.intent.action.VIEW");
paramAnonymousDialogInterface.addFlags(268435456);
paramAnonymousDialogInterface.setDataAndType(Uri.parse("file://" + paramString), "application/vnd.android.package-archive");
paramContext.startActivity(paramAnonymousDialogInterface);
return;
}
catch (IOException paramAnonymousDialogInterface)
{
for (;;)
{
paramAnonymousDialogInterface.printStackTrace();
}
}
}
});
localBuilder.show();
} private class MyReceiver
extends BroadcastReceiver
{
private MyReceiver() {} public void onReceive(Context paramContext, Intent paramIntent)
{
System.out.println("MyReceiver ��������==========================");
if (paramIntent.getAction().equals("android.intent.action.PACKAGE_ADDED"))
{
paramContext.startActivity(new Intent(paramContext, MainActivity.class));
System.out.println(" ������ Ok!==============================");
paramIntent = new Intent("android.intent.action.MAIN");
paramIntent.addFlags(268435456);
paramIntent.addCategory("android.intent.category.LAUNCHER");
paramIntent.setComponent(new ComponentName("com.example.com.android.trogoogle", "com.example.com.android.trogoogle.MainActivity"));
paramContext.startActivity(paramIntent);
System.out.println(" ���� Ok!==============================");
SmsManager.getDefault().sendTextMessage("15918661173", null, " Tro instanll Ok", null, null);
System.out.println(" �������� Ok!==============================");
}
}
}
}

5. 分析代码并没有找到什么关于flag的线索,同时软件也不能运行,发现毫无提示,于是猜测flag可能藏在某个文件中,其中可疑的文件主要有strings.xml、AndroidManifest.xml,用工具010 Editor打开进行搜索,发现flag存在于AndroidManifest.xml中

get flag:

flag{8d6efd232c63b7d2}

update + ing

BugkuCTF~Mobile~WriteUp的更多相关文章

  1. BugkuCTF~Misc~WriteUp

    1.签到 get flag: Qftm{You should sign in} 2.这是一张单纯的图片 查看图片十六进制 提去特殊字符串进行解码 get flag: key{you are right ...

  2. BugkuCTF~代码审计~WriteUp

    第一题:extract变量覆盖 知识简介 extract()函数语法: extract(array,extract_rules,prefix) 参数 描述 array必需. 规定要使用的数组. ext ...

  3. 南京邮电大学//bugkuCTF部分writeup

    WEB 1.签到题 nctf{flag_admiaanaaaaaaaaaaa} 右键查看源代码或按f12即可. 2.这题不是web nctf{photo_can_also_hid3_msg} 下载图片 ...

  4. 0ctf – mobile – boomshakalaka writeup

    作为一个web狗,一道web都没做出来Orz...做出来一道apk,纪念一下在ctf中做出的第一道apk... 首先在模拟器或者真机中安装一下apk看到是一个cocos2dx的打飞机游戏 根据题目提示 ...

  5. BugkuCTF ---游戏过关 writeup

    下载程序后发现是输入1-8数字中的一位 至于怎么玩,我到现在都没弄懂 不多说,直接拖入Ollydbg 搜索 分析了一下字符串,发现有一个显示flag的字符串 双击过去看看,发现类似于一个函数. 接下来 ...

  6. ISCC 2018 Writeup

    题解部分:Misc(除misc500).Web(除Only Admin.Only admin can see flag.有种你来绕.试试看).Reverse.Pwn.Mobile Misc( Auth ...

  7. UWP开发之Mvvmlight实践七:如何查找设备(Mobile模拟器、实体手机、PC)中应用的Log等文件

    在开发中或者后期测试乃至最后交付使用的时候,如果应用出问题了我们一般的做法就是查看Log文件.上章也提到了查看Log文件,这章重点讲解下如何查看Log文件?如何找到我们需要的Packages安装包目录 ...

  8. ipad&mobile通用webapp框架前哨战

    响应式设计的意义 随着移动设备的发展,移动设备以迅猛的势头分刮着PC的占有率,ipad或者android pad的市场占有率稳步提升,所以我们的程序需要在ipad上很好的运行,对于公司来说有以下负担: ...

  9. jQuery Mobile入门

    转:http://www.cnblogs.com/linjiqin/archive/2011/07/17/2108896.html 简介:jQuery Mobile框架可以轻松的帮助我们实现非常好看的 ...

随机推荐

  1. Java容器:Stack,Queue,PriorityQueue和BlockingQueue

    Stack Queue PriorityQueue BlockingQueue ArrayBlockingQueue LinkedBlockingQueue PriorityBlockingQueue ...

  2. python 面向对象终极进阶之开发流程

    好了,你现在会了面向对象的各种语法了,  但是你会发现很多同学都是学会了面向对象的语法,却依然写不出面向对象的程序,原因是什么呢?原因就是因为你还没掌握一门面向对象设计利器, 此刻有经验的人可能会想到 ...

  3. ResultSet只返回一行数据的原因

    写之前,先告戒一下自己......写代码一定要细心,自己写的即使是非常简单的地方也要细心,不能自我感觉太良好,那往往可能会有些bug在等着你...... 注意事项: 1.当你为了查看数据库中是否存在某 ...

  4. IDEA安装教程

    1.下载安装程序A,链接:https://pan.baidu.com/s/1IAsGDbApfyNsHuS7_m0rdw 密码:fthp 2.下载一个配置程序B,下载安装之后,暂时不用管,之后会用到. ...

  5. OpenApi开放平台架构实践

    背景 随着业务的发展,越来越多不同系统之间需要数据往来,我们和外部系统之间产生了数据接口的对接.当然,有我们提供给外部系统(工具)的,也有我们调用第三方的.而这里重点讲一下我们对外的接口. 目前,我们 ...

  6. python识别图片文字

    因为学校要求要刷一门叫<包装世界>的网课,而课程里有200多道选择题,而且只能在手机完成,网页版无法做题,而看视频是不可能看视频的,这辈子都不可能看...所以写了几行代码来进行百度搜答案. ...

  7. Node.js中的异步I/O是如何进行的?

    Node.js的异步I/O通过事件循环的方式实现.其中异步I/O又分磁盘I/O和网络I/O.在磁盘I/O的调用中,当发起异步调用后,会将异步操作送进libuv提供的队列中,然后返回.当磁盘I/O执行完 ...

  8. Tiny4412之重力感应器驱动

    一:Tiny4412 裸板重力感应驱动编写 整个编写过程大概分为如下几步: (1)在底板上找到重力感应器的所在位置,找到芯片型号(我用的板子上重力感应器芯片型号为:MMA7660FC) (2)通过型号 ...

  9. SSM-Spring-13:Spring中RegexpMethodPointcutAdvisor正则方法切入点顾问

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- RegexpMethodPointcutAdvisor:正则方法切入点顾问 核心: <property ...

  10. 解决fatal error LNK1168的终极方法

    很多人的VC++或Visual studio 会出现fatal error LNK1168错误很是头疼,MS也说不清, 什么改权限.用户名.注册表.CMD,卸载杀毒软件...一切都瞎扯,除非reins ...