安卓逆向百例十-币coin

2024-08-23 14:36
文章标签 逆向 安卓 百例 coin

本文主要是介绍安卓逆向百例十-币coin,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

typora-root-url: ./pic

安卓逆向百例十-币coin

现在售价依旧是99¥,计划更新100案例,平均一个案例1块钱,要什么自行车!

案例起源:

有位老哥 经过炒币失败后想做一个这种查询接口的app,但是苦于他的资金比较紧缺,就给我几百块,但是架不住苦苦哀求,我就做了,顺便当个案例。

版本: 币coin 4.0.3

包名: com.temperaturecoin

1.抓包分析

url是https://i.bicoin.com.cn/firmOffer/getUserAccountInfoBySecretNew?salt=8&sign=CDGCCEJCPCIGGGLICMVVBQOIEJTNNUQQN&time=1724126970032&userId=894919

位置在:


其中我们今天要去逆向的是 sign的生成,以及data的解密。

2.关键词定位

搜索

查找用例:

进入方法内 我们可以看的 sign是 经过了AESUtil.s

其中我们可以可以得到 :

time 就是时间戳 ,salt是一个 随机的值 sign 是 time + salt + "getUserAccountInfoBySecretNew"

接下来跳转到AESUtil.s 方法里面 跳转到这个位置:

hook验证一下入参:

查看一下加载的so文件是 ns:

打开ida 反编译 libns.so 搜索java我们发现是静态注册的 并且发现了 Java_com_bcoin_ns_S_s这个字眼:

进去看看喽!顺便把fastcall Java_com_bcoin_ns_S_s(int64 a1 的a1改成 JNIEnv *

jstring __fastcall Java_com_bcoin_ns_S_s(JNIEnv *a1, __int64 a2, __int64 a3)
{const char *v5; // x20const char *v6; // x21jstring result; // x0int v8; // w10__int64 (__fastcall *v9)(); // x10char v10; // w24int v11; // w9char *v12; // x20size_t v13; // w0char *v14; // x21unsigned __int64 v15; // x10char *v16; // x11unsigned __int64 v17; // x9char *v18; // x10char v19; // t1_OWORD *v20; // x12__int128 *v21; // x13unsigned __int64 v22; // x14__int128 v23; // q0__int128 v24; // q1_QWORD v25[2]; // [xsp+0h] [xbp-40h] BYREF
​v25[1] = *(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);v5 = (*a1)->GetStringUTFChars(a1, a3, 0LL);v6 = (*a1)->GetStringUTFChars(a1, token, 0LL);(*a1)->ReleaseStringUTFChars(a1, a3, v5);(*a1)->ReleaseStringUTFChars(a1, token, v6);result = 0LL;if ( v5 && v6 ){v8 = idxMethod % 3;if ( idxMethod % 3 ){if ( v8 == 2 ){v9 = jointMd5;v10 = 100;}else if ( v8 == 1 ){v9 = axor;v10 = 67;}else{v9 = chainXor;v10 = 97;}}else{v9 = cxor;v10 = 98;}if ( idxMethod == 2147483646 )v11 = 0;elsev11 = idxMethod + 1;idxMethod = v11;v12 = (v9)(v5, v6);__android_log_print(3, "bc", "pre payload: %s", v12);if ( v12 ){v13 = strlen(v12);v14 = v25 - ((v13 + 1 + 15LL) & 0x1FFFFFFF0LL);*v14 = v10;if ( v13 >= 1 ){if ( v13 > 0x1FuLL && (v14 + 1 >= &v12[v13] || v12 >= &v14[v13 + 1]) ){v15 = v13 - (v13 & 0x1F);v20 = v14 + 17;v21 = (v12 + 16);v22 = v15;do{v23 = *(v21 - 1);v24 = *v21;v22 -= 32LL;v21 += 2;*(v20 - 1) = v23;*v20 = v24;v20 += 2;}while ( v22 );if ( (v13 & 0x1F) == 0 )goto LABEL_21;}else{v15 = 0LL;}v16 = &v12[v15];v17 = v13 - v15;v18 = &v14[v15 + 1];do{v19 = *v16++;--v17;*v18++ = v19;}while ( v17 );}
LABEL_21:v14[v13 + 1] = 0;free(v12);return (*a1)->NewStringUTF(a1, v14);}return (*a1)->NewStringUTF(a1, "");}return result;
}

眼尖的朋友已经看见了 这里有个 __android_log_print 我们可以使用adb 来监控他的输出

在设备上运行日志记录工具 logcat,这是 Android 提供的一个工具,用于实时查看系统和应用程序的日志。

在终端中执行以下命令启动 logcat

adb logcat

这会显示设备上的所有日志信息。如果你想要过滤特定标签(例如 "bc"),可以使用:

adb logcat -s bc:D

这里的 -s 选项指定了过滤的标签,D 表示只显示 DEBUG 级别及以上的日志。

logcat:524b5a6860bad1a0bbe0712e48a5debb

抓包:d524b5a6860bad1a0bbe0712e48a5debb

我们从中可以发现 其实就是 结果 加了一个d 对吧,但是我们通过观察 logcat 和 抓包会发现有的时候是大写 有的时候是小写而且规律也不一样。他其实和这个有关系

这段代码根据 idxMethod 的值选择一个函数指针,并根据不同的条件设置函数的参数和值。接着调用这个函数,并将结果保存到 v12 中。代码的目的是根据不同的条件选择合适的处理函数,并在每次调用后更新 idxMethod 的值。

代码解释:

result = 0LL; // 初始化一个 long long 类型的变量 result 为 0
​
if (v5 && v6) // 如果 v5 和 v6 都不为 0(即它们都有效)
{v8 = idxMethod % 3; // 计算 idxMethod 除以 3 的余数,并将结果赋值给 v8
​if (idxMethod % 3) // 如果 idxMethod 除以 3 的余数不为 0{if (v8 == 2) // 如果余数是 2{v9 = jointMd5; // 将 v9 设置为 jointMd5(假设 jointMd5 是一个函数指针)v10 = 100; // 将 v10 设置为 100}else if (v8 == 1) // 如果余数是 1{v9 = axor; // 将 v9 设置为 axor(假设 axor 是一个函数指针)v10 = 67; // 将 v10 设置为 67}else // 如果余数是 0{v9 = chainXor; // 将 v9 设置为 chainXor(假设 chainXor 是一个函数指针)v10 = 97; // 将 v10 设置为 97}}else // 如果 idxMethod 除以 3 的余数为 0{v9 = cxor; // 将 v9 设置为 cxor(假设 cxor 是一个函数指针)v10 = 98; // 将 v10 设置为 98}
​if (idxMethod == 2147483646) // 如果 idxMethod 的值为 2147483646v11 = 0; // 将 v11 设置为 0elsev11 = idxMethod + 1; // 否则,将 v11 设置为 idxMethod + 1
​idxMethod = v11; // 更新 idxMethod 的值为 v11
​v12 = (v9)(v5, v6); // 调用 v9 指向的函数,传入 v5 和 v6 作为参数,并将结果赋值给 v12
}
​

我们这里可以直接看他走 jointMd5 的位置 然后 直接查看入参不就行了 ,然后固定参数去请求。这样就不用还原 chainXor 和 cxor 函数了。

我们查看joinmd5这个函数 映入眼帘的是 这两个

v8 = strcpy(v6, s); 
​
strcat(v8, a1);

所以我直接去hook joinMd5 这个函数:

args1来源token:

抓包和adb 记录的:

所以就是 MD5(token + times + salt + 'getUserAccountInfoBySecretNew') 这个已经验证过了是标准的md5

str = '2c06cef65865431546fdb751f255508b'+str(times)+"6"+'getUserAccountInfoBySecretNew'
# print(str)
sign = 'd'+calculate_md5(str)

所以我们请求的时候 固定salt 就行了

具体代码放在文章最后...

3.返回值解密

一般来说 同一个数据包的加密的位置在都在一块,所以我们就顺藤摸瓜,就找到

hook验证:

去so层看看 :

一进去我们就看到 AES 128 pkcs5 的字眼:

进来后发现:

好家伙 Key = getKey(); IV = getIV(); 这么明显吗?那就不怪我了

上frida hook: hook到key 和 iv了

hook代码如下:

​
// key
var addr = Module.findBaseAddress('libns.so');
var KEY = addr.add(0x10144);
console.log(KEY);
Interceptor.attach(KEY,{onEnter:function (args){console.log("---------key 进入了-----------")
​},onLeave:function(retval) {console.log("--------------------")console.log('KEY 返回值:',hexdump(retval,{length:16}))}
})
// IV
var addr = Module.findBaseAddress('libns.so');
var IV = addr.add(0x10144);
console.log(IV);
Interceptor.attach(IV,{onEnter:function (args){console.log("---------IV 进入了-----------")
​},onLeave:function(retval) {console.log("--------------------")console.log('IV 返回值:',hexdump(retval,{length:16}))}
})

至此我们整个流程就已经完成了。

4.python代码还原

import time
from loguru import logger
import requests
​
import hashlib
from Crypto.Cipher import AES
import base64
import requests
​
def unpad(data):"""去除填充"""pad_length = data[-1]return data[:-pad_length]
def decrypt_aes_cbc(ciphertext_base64, key, iv):# key = bytes(key_text, 'utf-8')# iv = bytes(iv_text, 'utf-8')ciphertext = base64.b64decode(ciphertext_base64)
​cipher = AES.new(key, AES.MODE_CBC, iv)plaintext = cipher.decrypt(ciphertext)plaintext = unpad(plaintext).decode('utf-8')return plaintext
def calculate_md5(data):# 创建一个MD5哈希对象md5_hash = hashlib.md5()# 更新哈希对象md5_hash.update(data.encode('utf-8'))# 返回MD5哈希的十六进制表示return md5_hash.hexdigest()
​
headers = {xxx
}
times = int(time.time() * 1000)
# 17236209670982
# 1723621530537
# 1723621708604
# print(times)
str = 'token'+str(times)+"6"+'getUserAccountInfoBySecretNew'
# print(str)
sign = 'd'+calculate_md5(str)
logger.info("sign签名{}".format(sign))
# print(sign)
headers['Sign'] = sign
headers['Time'] = f'{times}'
url = "https://i.bicoin.com.cn/firmOffer/getUserAccountInfoBySecretNew"
params = {"salt": "6","sign": f"{sign}","time": f"{times}","userId": "894919"
}
response = requests.get(url, headers=headers, params=params).json()
print(response)
data = response['data']
key_hex = '8971483f9910300bdffee864cb135f34'
iv_hex = '8971483f9910300bdffee864cb135f34'
data = decrypt_aes_cbc(data, bytes.fromhex(key_hex), bytes.fromhex(iv_hex))
print(data)
#2c06cef65865431546fdb751f255508b17236221106396getUserAccountInfoBySecretNew
#2c06cef65865431546fdb751f255508b17236215305376getUserAccountInfoBySecretNew
交流群:

这篇关于安卓逆向百例十-币coin的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1099655

相关文章

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法   消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法 [转载]原地址:http://blog.csdn.net/x605940745/article/details/17911115 消除SDK更新时的“

Android逆向(反调,脱壳,过ssl证书脚本)

文章目录 总结 基础Android基础工具 定位关键代码页面activity定位数据包参数定位堆栈追踪 编写反调脱壳好用的脚本过ssl证书校验抓包反调的脚本打印堆栈bilibili反调的脚本 总结 暑假做了两个月的Android逆向,记录一下自己学到的东西。对于app渗透有了一些思路。 这两个月主要做的是代码分析,对于分析完后的持久化等没有学习。主要是如何反编译源码,如何找到

安卓玩机工具------小米工具箱扩展工具 小米机型功能拓展

小米工具箱扩展版                     小米工具箱扩展版 iO_Box_Mi_Ext是由@晨钟酱开发的一款适用于小米(MIUI)、多亲(2、2Pro)、多看(多看电纸书)的多功能工具箱。该工具所有功能均可以免root实现,使用前,请打开开发者选项中的“USB调试”  功能特点 【小米工具箱】 1:冻结MIUI全家桶,隐藏状态栏图标,修改下拉通知栏图块数量;冻结

转:android ro.debuggable属性调试修改(mprop逆向)

android ro属性调试修改(mprop逆向)      大家都知道如果需要调试android 的程序,以下两个条件满足一个就行。第一是apk的配置文件内的AndroidManifest.xml的 android:debuggable=”true”,第二就是/default.prop中ro.debuggable=1。两种方式第一种通常是解包添加属性再打包,随着加壳软件以及apk校验等,容易出

安卓开发板_联发科MTK开发评估套件串口调试

串口调试 如果正在进行lk(little kernel ) 或内核开发,USB 串口适配器( USB 转串口 TTL 适配器的简称)对于检查系统启动日志非常有用,特别是在没有图形桌面显示的情况下。 1.选购适配器 常用的许多 USB 转串口的适配器,按芯片来分,有以下几种: CH340PL2303CP2104FT232 一般来说,采用 CH340 芯片的适配器,性能比较稳定,价

某里227逆向分析

声明: 该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关。 本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除! 前言 这次会简单的讲解阿里227版本滑块参数n的逆向分析流程以及简单的补环境,如果有疑问可以在评论区交流讨论,我看到会及时回复的,另外,有需要可联系我。 一

安卓实现弹出软键盘屏幕自适应调整

今天,我通过尝试诸多方法,最终实现了软键盘弹出屏幕的自适应。      其实,一开始我想通过EditText的事件来实现,后来发现,安卓自带的函数十分强大,只需几行代码,便可实现。实现如下:     在Manifest中设置activity的属性:android:windowSoftInputMode="adjustUnspecified|stateHidden|adjustResi

674 - Coin Change

一道很水的DP,但我做的时候也很费劲,由于存在面值为1的时候,所以所有面额都至少有1种方法。 推导出状态方程就是 dp(V,step) += dp(V - i * coin[step],step - 1); 其中V为当前的面值,coin[step]为硬币的面额,递归边界,如果step == 0(也就是递归到硬币面额为1的时候,返回1); #include<cstdio>#include<

【MyBatis学习14】MyBatis的逆向工程生成代码

1. 什么是逆向工程 mybatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代码(包括mapper.xml、mapper.java、po..)。一般在开发中,常用的逆向工程方式是通过数据库的表生成代码。 2. 使用逆向工程 使用mybatis的逆向工程,需要导入逆向