技术标签: app android 定位 android studio ssl
前言
Android逆向是一个很大很深的话题,我们这个系列探讨的是爬虫工程师日常的逆向需求,比如签名算法啊,post请求中的加密啊,乱七八糟的随机字段等,下面看看我们每次要分析的app。
抓包
抓包前将手机和电脑连接到同一WIFI,在手机设置好代理,装好证书,就可以开始抓包了,抓包工具随意
抓包环境配置好后,在注册页面随便输入一个账号,然后点击注册
查看抓到的数据包,找需要分析的参数进行分析
deviceCode 是IMEI 码,这次逆向的重点也就是分析sign,appcode生成逻辑。
分析
看到这个sign 我首先想到用objection trace 一下,没了解过 objection的可以自行百度,也可以参考roysue的文章:
https://www.anquanke.com/post/id/197657?from=timeline&isappinstalled=0
使用命令:
android hooking search classes sign
找到含有sign的类
其中有条成功引起了我的注意,找的时候先查找携带包名的类,然后触发一下:
android hooking watch class com.******hotel.app.whnetcomponent.utils.SignUtil
触发后得到以下结果,又发现两个比较可疑的方法,继续跟踪:
android hooking watch class_method com.******wehotel.app.whnetcomponent.utils.SignUtil.getAppCode --dump-args --dump-return
android hooking watch class_method com.******wehotel.app.whnetcomponent.utils.SignUtil.getSignString --dump-args --dump-return
再次触发后看到拿到的正好是我们需要的结果,这样就定位到了参数位置:
现在我们去看看app 代码。
脱壳加验证
这个app 使用某数字壳,直接使用葫芦娃的脱壳工具:
https://github.com/hluwa/FRIDA-DEXDump
对于体积比较大的app来说,使用dex-finder能让我们更快速的查看需要的类和参数,Gitub地址:
https://github.com/LeadroyaL/dex-finder
找到我们需要查看的类所在的dex,使用命令:
使用下面命令
java -jar dex-finder.jar -f 目录 -c com.******wehotel.app.whnetcomponent.utils.SignUtil
找到我们需要的dex后 ,用jadx 打开查看:
一眼就能看见sign 是md5,appcode 是AES加密,然后跟进去就找到了key,加密模式和填充方式
AesUtil.encrypt(timestamp + "+" + ascii + "+" + devicesNo + "+" + latlng);
1585278419269, 51405, 00000000-30ae-6a3e-a3c1-fe290033c587, 0,0
1585274763545+1974+00000000-30ae-6a3e-a3c1-fe290033c587+0,0
这里可以看到ascii ,但是不知道怎么来的,打印下堆栈,然后去上一级找,很快找到了生成位置decodeASCII,
Python改写如下:
query = {"systemVersion":"5.1.1", "sid":"306259","userId":"0", "mobile":mobile, "clientVersion":"4.2.9", "deviceType":"google Pixel 2","nationCode":"86","deviceCode":"865166010285875"}
k = list(query.values())
asc = str(sum([sum([ord(i) for i in j]) for j in k ]))
然后接下来看sign ,加密方式就是这样,hook 下参数:
md5.getMD5ofStr(md5.getMD5ofStr(userId + appChannel + devicesNo + timestamp + latlng + ascii) + timestamp + ascii + devicesNo + latlng);
0, vadjlr4k3o;qj4io23ug9034uji5rjn34io5u83490u5903huq, 00000000-30ae-6a3e-a3c1-fe290033c587, 1585278419367, 0,0, 1974
"0vadjlr4k3o;qj4io23ug9034uji5rjn34io5u83490u5903huq00000000-30ae-6a3e-a3c1-fe290033c58715852784193670,01974"
B4BB10ECF03A740174AFABA1EC93E00E1585278419367197400000000-30ae-6a3e-a3c1-fe290033c5870,0
A298CD04C866C7F0BF9E0D4456AFD7B1
A298CD04C866C7F0BF9E0D4456AFD7B1
两次md5 对比后发现appChannel是固定,其他就可以自己伪造了
最后再说下 deviceId 的生成方式,其实不重要,uuid伪造就行了,
clientInfo.setDeviceId(new UUID((long) androidId.hashCode(), (((long) tmDevice.hashCode()) << 32) | ((long) tmSerial.hashCode())).toString());
到此 分析完毕,Python改写请求即可:
// 下面是验证参数用到的fria脚本
function showStacks() {
Java.perform(function() {
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
});
}
function hook(){
Java.perform(function(){
var util = Java.use('com.******wehotel.app.whnetcomponent.net.JJSignInterceptor');
var Buffer = Java.use("okio.Buffer");
var aci = Java.use("com.******wehotel.app.whnetcomponent.utils.SignUtil")
var device = Java.use("com.******wehotel.app.whnetcomponent.utils.DeviceUtil");
var ut = Java.use("com.******wehotel.app.whnetcomponent.utils.Utils");
var client = Java.use("com.******hotel.app.whnetcomponent.net.ClientInfo");
var WHGetDeviceIdUtil = Java.use("com.******hotel.app.componentservice.WHGetDeviceIdUtil");
var Settings = Java.use("android.provider.Settings$Secure");
var TelephonyManager = Java.use("android.telephony.TelephonyManager");
var UUID = Java.use("java.util.UUID");
util.handlerRequest.implementation = function (request) {
showStacks();
var ret = this.handlerRequest(request);
console.log(request);
try {
console.log("MyInterceptor.intercept onEnter:", request, "\nrequest headers:\n", request.headers());
var requestBody = request.body();
var contentLength = requestBody ? requestBody.contentLength() : 0;
if (contentLength > 0) {
var BufferObj = Buffer.$new();
requestBody.writeTo(BufferObj);
console.log("\nrequest body String:\n", BufferObj.readUtf8(), "\n");
};
} catch (error) {
console.log("error 1:", error);
};
console.log(ret);
var context = ut.getApp();
var a = device.readClientInfo(context);
var tmDevice = "" + WHGetDeviceIdUtil.getDeviceId(context);
var pm = context.getSystemService("phone")
var b = Java.cast(pm,TelephonyManager);
var tmSerial = b.getSimSerialNumber();
var androidId = "" + Settings.getString(context.getContentResolver(), "android_id");
console.log(tmDevice,tmSerial,androidId);
console.log(a.getDeviceId());
return ret;
}
aci.decodeASCII.implementation = function (a) {
// showStacks();
console.log(a);
var ret = this.decodeASCII(a);
console.log(ret);
return ret;
};
aci.stringToAscII.implementation = function (a) {
// showStacks();
console.log(a);
var ret = this.stringToAscII(a);
console.log(ret);
return ret;
};
UUID.$init.implementation = function (a,b) {
// showStacks();
console.log("a",a);
console.log("b",b);
var ret = this.$init(a,b);
};
});
};
setImmediate(function(){
setTimeout(hook, 2000);
});
大功告成!就这样,下次再见。
文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr
文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc
文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8
文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束
文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求
文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname
文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include<stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>#include<iostream>#include<stack>#include<queue>using namespace std;typed_二叉树的建立
文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码
文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词
文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限
文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定
文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland