objectioin实战详解

接上篇,上篇对Objection的常用使用方法进行了总结,同时也找到两个APK进行练习测试。

文章中使用的APK以及脚本可以在此处进行下载 Demo下载

objection.png

Junior

下载

frida, objection等版本可见上篇
# 测试环境
Mac OS 12.3
Kali 2022
Nexus 6P
MUMU模拟器
// 安装
╰─$ adb install -t junior.apk
Performing Push Install
junior.apk: 1 file pushed, 0 skipped. 16.1 MB/s (2347060 bytes in 0.139s)
pkg: /data/local/tmp/junior.apk
Success

源代码地址: Junior

image-20230128154133320

安装成功后首先使用Objection 遍历一下App的所有Activity

objection -g com.example.junior explore -P ~/.objection/plugins
com.example.junior on (Android: 6.0.1) [usb] # android hooking list activities
com.example.junior.BbsActivity
com.example.junior.CalculatorActivity
com.example.junior.CaptureActivity
com.example.junior.ClickActivity
com.example.junior.ColorActivity
com.example.junior.GravityActivity
com.example.junior.IconActivity
com.example.junior.MainActivity
com.example.junior.MarginActivity
com.example.junior.MarqueeActivity
com.example.junior.NineActivity
com.example.junior.PxActivity
com.example.junior.ScaleActivity
com.example.junior.ScreenActivity
com.example.junior.ScrollActivity
com.example.junior.ShapeActivity
com.example.junior.StateActivity

Found 17 classes

我们启动其计算器功能

com.example.junior on (Android: 6.0.1) [usb] # android intent launch_activity com.example.junior.CalculatorActivity
(agent) Starting activity com.example.junior.CalculatorActivity...
(agent) Activity successfully asked to start.
image-20230128160517143

OnCreate()

查看CalculatorActivity.java的onCreate函数

image-20230128160926754

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calculator);
// 从布局文件中获取名叫tv_result的文本视图
tv_result = findViewById(R.id.tv_result);
// 设置tv_result内部文本的移动方式为滚动形式
tv_result.setMovementMethod(new ScrollingMovementMethod());
// 下面给每个按钮控件都注册了点击监听器
findViewById(R.id.btn_cancel).setOnClickListener(this); // “取消”按钮
findViewById(R.id.btn_divide).setOnClickListener(this); // “除法”按钮
findViewById(R.id.btn_multiply).setOnClickListener(this); // “乘法”按钮
findViewById(R.id.btn_clear).setOnClickListener(this); // “清除”按钮
findViewById(R.id.btn_seven).setOnClickListener(this); // 数字7
findViewById(R.id.btn_eight).setOnClickListener(this); // 数字8
findViewById(R.id.btn_nine).setOnClickListener(this); // 数字9
findViewById(R.id.btn_plus).setOnClickListener(this); // “加法”按钮
findViewById(R.id.btn_four).setOnClickListener(this); // 数字4
findViewById(R.id.btn_five).setOnClickListener(this); // 数字5
findViewById(R.id.btn_six).setOnClickListener(this); // 数字6
findViewById(R.id.btn_minus).setOnClickListener(this); // “减法”按钮
findViewById(R.id.btn_one).setOnClickListener(this); // 数字1
findViewById(R.id.btn_two).setOnClickListener(this); // 数字2
findViewById(R.id.btn_three).setOnClickListener(this); // 数字3
findViewById(R.id.btn_zero).setOnClickListener(this); // 数字0
findViewById(R.id.btn_dot).setOnClickListener(this); // “小数点”按钮
findViewById(R.id.btn_equal).setOnClickListener(this); // “等号”按钮
findViewById(R.id.ib_sqrt).setOnClickListener(this); // “开平方”按钮
}

测试这个计算机之后回发现,每次按“等号”按钮后计算结果都会被打印出来。根据这一现象,找到对应的点击响应函数onClick()函数中属于“等号”按钮的源码部分,最终的源码如下

OnClick()

@Override
public void onClick(View v) {
int resid = v.getId(); // 获得当前按钮的编号
String inputText;
if (resid == R.id.ib_sqrt) { // 如果是开根号按钮
inputText = "√";
} else { // 除了开根号按钮之外的其它按钮
inputText = ((TextView) v).getText().toString();
}
Log.d(TAG, "resid=" + resid + ",inputText=" + inputText);
if (resid == R.id.btn_clear) { // 点击了清除按钮
clear("");
} else if (resid == R.id.btn_cancel) { // 点击了取消按钮
if (operator.equals("")) { // 无操作符,则表示逐位取消前一个操作数
if (firstNum.length() == 1) {
firstNum = "0";
} else if (firstNum.length() > 0) {
firstNum = firstNum.substring(0, firstNum.length() - 1);
} else {
Toast.makeText(this, "没有可取消的数字了", Toast.LENGTH_SHORT).show();
return;
}
showText = firstNum;
tv_result.setText(showText);
} else { // 有操作符,则表示逐位取消后一个操作数
if (nextNum.length() == 1) {
nextNum = "";
} else if (nextNum.length() > 0) {
nextNum = nextNum.substring(0, nextNum.length() - 1);
} else {
Toast.makeText(this, "没有可取消的数字了", Toast.LENGTH_SHORT).show();
return;
}
showText = showText.substring(0, showText.length() - 1);
tv_result.setText(showText);
}
} else if (resid == R.id.btn_equal) { // 点击了等号按钮
if (operator.length() == 0 || operator.equals("=")) {
Toast.makeText(this, "请输入运算符", Toast.LENGTH_SHORT).show();
return;
} else if (nextNum.length() <= 0) {
Toast.makeText(this, "请输入数字", Toast.LENGTH_SHORT).show();
return;
}
if (caculate()) { // 计算成功,则显示计算结果
operator = inputText;
showText = showText + "=" + result;
tv_result.setText(showText);
} else { // 计算失败,则直接返回
return;
}
} else if (resid == R.id.btn_plus || resid == R.id.btn_minus // 点击了加、减、乘、除按钮
|| resid == R.id.btn_multiply || resid == R.id.btn_divide) {
if (firstNum.length() <= 0) {
Toast.makeText(this, "请输入数字", Toast.LENGTH_SHORT).show();
return;
}
if (operator.length() == 0 || operator.equals("=") || operator.equals("√")) {
operator = inputText; // 操作符
showText = showText + operator;
tv_result.setText(showText);
} else {
Toast.makeText(this, "请输入数字", Toast.LENGTH_SHORT).show();
return;
}
} else if (resid == R.id.ib_sqrt) { // 点击了开根号按钮
if (firstNum.length() <= 0) {
Toast.makeText(this, "请输入数字", Toast.LENGTH_SHORT).show();
return;
}
if (Double.parseDouble(firstNum) < 0) {
Toast.makeText(this, "开根号的数值不能小于0", Toast.LENGTH_SHORT).show();
return;
}
// 进行开根号运算
result = String.valueOf(Math.sqrt(Double.parseDouble(firstNum)));
firstNum = result;
nextNum = "";
operator = inputText;
showText = showText + "√=" + result;
tv_result.setText(showText);
Log.d(TAG, "result=" + result + ",firstNum=" + firstNum + ",operator=" + operator);
} else { // 点击了其它按钮,包括数字和小数点
if (operator.equals("=")) { // 上一次点击了等号按钮,则清空操作符
operator = "";
firstNum = "";
showText = "";
}
if (resid == R.id.btn_dot) { // 点击了小数点
inputText = ".";
}
if (operator.equals("")) { // 无操作符,则继续拼接前一个操作数
if (firstNum.contains(".") && inputText.equals(".")) {
return; // 一个数字不能有两个小数点
}
firstNum = firstNum + inputText;
} else { // 有操作符,则继续拼接后一个操作数
if (nextNum.contains(".") && inputText.equals(".")) {
return; // 一个数字不能有两个小数点
}
nextNum = nextNum + inputText;
}
showText = showText + inputText;
tv_result.setText(showText);
}
return;
}

可以看到btn_equal主要是在caculate()函数中 接下来我们使用objection来验证一下是否存在caculate()函数

com.example.junior on (Android: 6.0.1) [usb] # android hooking list class_methods com.example.junior.CalculatorActivity
private boolean com.example.junior.CalculatorActivity.caculate()
private void com.example.junior.CalculatorActivity.clear(java.lang.String)
protected void com.example.junior.CalculatorActivity.onCreate(android.os.Bundle)
public void com.example.junior.CalculatorActivity.onClick(android.view.View)

Found 4 method(s)

calculate()

private boolean caculate() {
if (operator.equals("+")) { // 当前是相加运算
result = String.valueOf(Arith.add(firstNum, nextNum));
} else if (operator.equals("-")) { // 当前是相减运算
result = String.valueOf(Arith.sub(firstNum, nextNum));
} else if (operator.equals("×")) { // 当前是相乘运算
result = String.valueOf(Arith.mul(firstNum, nextNum));
} else if (operator.equals("÷")) { // 当前是相除运算
if (Double.parseDouble(nextNum) == 0) { // 发现被除数是0
// 被除数为0,要弹窗提示用户
Toast.makeText(this, "被除数不能为零", Toast.LENGTH_SHORT).show();
// 返回false表示运算失败
return false;
} else { // 被除数非0,则进行正常的除法运算
result = String.valueOf(Arith.div(firstNum, nextNum));
}
}
// 把运算结果打印到日志中
Log.d(TAG, "result=" + result);
firstNum = result;
nextNum = "";
// 返回true表示运算成功
return true;
}

在这个函数中对减法的处理是调用Arith.sub函数实现的 我们通常使用objeciton来获取一个应用在内存中的所有类

android hooking list classes
com.example.junior on (google: 6.0.1) [usb] # android hooking list class_methods com.example.junior.util.Arith
public static java.lang.String com.example.junior.util.Arith.add(double,double)
public static java.lang.String com.example.junior.util.Arith.add(java.lang.String,java.lang.String)
public static java.lang.String com.example.junior.util.Arith.div(double,double)
public static java.lang.String com.example.junior.util.Arith.div(double,double,int)
public static java.lang.String com.example.junior.util.Arith.div(java.lang.String,java.lang.String)
public static java.lang.String com.example.junior.util.Arith.div(java.lang.String,java.lang.String,int)
public static java.lang.String com.example.junior.util.Arith.mul(double,double)
public static java.lang.String com.example.junior.util.Arith.mul(java.lang.String,java.lang.String)
public static java.lang.String com.example.junior.util.Arith.round(double,int)
public static java.lang.String com.example.junior.util.Arith.sub(double,double)
public static java.lang.String com.example.junior.util.Arith.sub(java.lang.String,java.lang.String)

Found 11 method(s)

Ps: objection使用 android hooking list classes 缓存太大时可以使用如下方法

删除~/.objection/objection.log
重新加载,调用在cat 即可
╰─$ cat ~/.objection/objection.log | grep com.example.junior
com.example.junior.CalculatorActivity
com.example.junior.MainActivity
com.example.junior.util.Arith

Util.Arith()

在内存中确定util.Arith() 函数后,便可以直接对这个函数进行hook

com.example.junior on (Android: 6.0.1) [usb] # android hooking watch class_method com.example.junior.util.Arith.sub --dump-args --
dump-backtrace --dump-return
(agent) Attempting to watch class com.example.junior.util.Arith and method sub.
(agent) Hooking com.example.junior.util.Arith.sub(double, double)
(agent) Hooking com.example.junior.util.Arith.sub(java.lang.String, java.lang.String)
(agent) Registering job gj9zcimwkem. Type: watch-method for: com.example.junior.util.Arith.sub

之后在计算器中随机进行减法操作

image-20230128163238577

在objection中已经hook到util.Arith()函数

com.example.junior on (Android: 6.0.1) [usb] # (agent) [gj9zcimwkem] Called com.example.junior.util.Arith.sub(java.lang.String, java.lang.String)
(agent) [gj9zcimwkem] Arguments com.example.junior.util.Arith.sub(12, 5)
(agent) [gj9zcimwkem] Return Value: 7

对所有运算函数进行hook

com.example.junior on (Android: 6.0.1) [usb] # jobs list
Job ID Hooks Type
----------- ----- ---------------------------------------------------
gj9zcimwkem 2 watch-method for: com.example.junior.util.Arith.sub
7lyewxvtoip 2 watch-method for: com.example.junior.util.Arith.add
hsdvh65digm 2 watch-method for: com.example.junior.util.Arith.mul
i5opzx0y42e 4 watch-method for: com.example.junior.util.Arith.div

同时编写frida脚本进行Hook

hook.js

frida -F -l hook.js

function main(){
Java.perform(function(){
var Arith = Java.use('com.example.junior.util.Arith')
Arith.sub.implementation = function(str,str2){
var result = this.sub(str,str2)
console.log("str,str2,result=>", str,str2,result)
//return result
//打印Java调用栈
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()))
return result
}

})
}
setImmediate(main)

发现存在报错

[Android Emulator 5554::com.example.junior]-> Error: sub(): has more than one overload, use .overload(<signature>) to choose from:
.overload('java.lang.String', 'java.lang.String')
.overload('double', 'double')
at throwOverloadError (frida/node_modules/frida-java-bridge/lib/class-factory.js:1020)
at frida/node_modules/frida-java-bridge/lib/class-factory.js:707
at /hook.js:11
at frida/node_modules/frida-java-bridge/lib/vm.js:11
at E (frida/node_modules/frida-java-bridge/index.js:346)
at frida/node_modules/frida-java-bridge/index.js:332
at input:1

我们根据之前Objection的结果

com.example.junior on (Android: 6.0.1) [usb] # (agent) [gj9zcimwkem] Called com.example.junior.util.Arith.sub(java.lang.String, java.lang.String)

overload(‘java.lang.String’,’java.lang.String’)添加到代码中即可

function main(){
Java.perform(function(){
var Arith = Java.use('com.example.junior.util.Arith')
Arith.sub.overload('java.lang.String','java.lang.String').implementation = function(str,str2){
var result = this.sub(str,str2)
console.log("str,str2,result=>", str,str2,result)
//return result
//打印Java调用栈
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()))
return result
}

})
}

setImmediate(main)

image-20230128165354224

使用脚本对参数进行修改,将第二个参数修改为123

function main(){
Java.perform(function(){
var Arith = Java.use('com.example.junior.util.Arith')
Arith.sub.overload('java.lang.String','java.lang.String').implementation = function(str,str2){
var result = this.sub(str,"123")
console.log("str,str2,result=>", str,str2,result)
//return result
//打印Java调用栈
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()))
return result
}

})
}

setImmediate(main)

image-20230128165529840

Ps: 这里123的直接传递实际上是不对的,正确的传入字符串参数的方式应该如夏,也就是使用Java中相应字符串类新建一个字符串实例传参

var JavaString = Java.use("java.lang.String")
var result = this.sub(str, JavaString.$new('123')))

这里我们去构造的新的参数的类型是根据实际函数的第二个参数类型为java.lang.String 决定的。之所以用this.sub(str,”123”)的方式传递字符串时没有报错,是因为Frida本身对JavaScript的字符串进行了转换,将JavaScript的字符串在内部转换位了Java的String类型。如果是复杂的参数,就一定要先调用Java.use() 这个APi去获取对应的类对象,然后通过$new()函数去构造一个新的参数

call.js

function callSub(){
Java.perform(function(){
var Arith = Java.use('com.example.junior.util.Arith')
var JavaString = Java.use('java.lang.String')
var result = Arith.sub(JavaString.$new("123"),JavaString.$new("111"))
console.log("123 - 111 = ", result)
})
}
[Android Emulator 5554::com.example.junior]-> callSub()
123 - 111 = 12

Rpc调用

call.js

function CallSub(a,b){
Java.perform(function(){
var Arith = Java.use('com.example.junior.util.Arith')
var JavaString = Java.use('java.lang.String')
var result = Arith.sub(JavaString.$new(a),JavaString.$new(b))
console.log(a,"-",b,"=",result)
})
}

rpc.exports = {
sub : CallSub
}


/*
rpc.exports = {
sub: function CallSub(a,b){
Java.perform(function(){
var Arith = Java.use('com.example.junior.util.Arith')
var JavaString = Java.use('java.lang.String')
var result = Arith.sub(JavaString.$new(a),JavaString.$new(b))
console.log(a,"-",b,"=",result) // 最终修改为 send(a,"-",b,"=",result)
})

}
}
*/

loader.py

from distutils import command
import frida, sys

def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)

device = frida.get_usb_device()

# frida-server -l 0.0.0.0:1
# device = frida.get_devices_manager().add_remote_device('192.168.50.129:1234')

process = device.attach('com.example.junior')

with open('call.js') as f:
jscode = f.read()

script = process.create_script(jscode)

script.on('message', on_message)
script.load()

for i in range(20,30):
for j in range(0,10):
script.exports.sub(str(i),str(j))

调用结果

python3 loader.py                                                                            1 ↵
20 - 0 = 20
20 - 1 = 19
20 - 2 = 18
20 - 3 = 17
20 - 4 = 16
20 - 5 = 15
20 - 6 = 14
20 - 7 = 13
20 - 8 = 12
20 - 9 = 11
21 - 0 = 21
21 - 1 = 20
21 - 2 = 19
21 - 3 = 18
21 - 4 = 17
21 - 5 = 16
21 - 6 = 15
21 - 7 = 14

yry-1.0.apk

该APK为恶意锁机勒索病毒,建议在沙箱,模拟器或者在无人情况进行学习。主要恶意行为如下

  • 背景图片和背景音乐极其不健康,音量调到最大,循环播放,且无法关闭
  • 屏幕被锁定,无法进行任何操作
  • USB断开
  • 手机持续震动,并存在自启动服务

Ps: 由于会断开USB连接,这边推荐3钟方式进行测试

1.使用WIFI ADB在手机上开启远程ADB服务进行连接
2.使用模拟器进行测试
3.修改Smali代码,重打包 //apktool编译重打包 ,keytool制作密钥库,apksigner对apk签名

image-20230129083855272

image-20230129083920125

安装后使用objection连接应用,静态分析文件,并遍历services服务。

com.shimeng.qq2693533893 on (Android: 6.0.1) [usb] # android hooking list services
com.shimeng.qq2693533893.MyServiceOne

Found 1 classes
package com.shimeng.qq2693533893;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;

/* loaded from: classes.dex */
public class MainActivity extends Activity {
@Override // android.app.Activity
protected void onCreate(Bundle bundle) {
LogCatBroadcaster.start(this);
super.onCreate(bundle);
try {
startService(new Intent(this, Class.forName("com.shimeng.qq2693533893.MyServiceOne")));
} catch (ClassNotFoundException e) {
throw new NoClassDefFoundError(e.getMessage());
}
}
}

静态分析后,我们初步确定这个App的核心方法应该在MyserviceOne服务中,但是并不确定具体是哪个函数,所以直接使用命令Hook整个类。

android hooking watch class com.shimeng.qq2693533893.MyServiceOne --dump-args --dump-backtrace --dump-return

image-20230129084728970

使用objection查看对应类的函数方法。

com.shimeng.qq2693533893 on (Android: 6.0.1) [usb] # plugin wallbreaker classdump com.shimeng.qq2693533893.MyServiceOne --fullname

package com.shimeng.qq2693533893

class MyServiceOne {

/* static fields */
static java.lang.String KEY; => 颜如玉QQ:2693533893
static java.lang.String KEYIV; => EDC9381060B95338
static boolean hexcase; => false
static java.lang.String 月如意; => 8D4FF507DCDA63C201EB8B99D4170900
static java.lang.String 破解死全家; => 23543dfggeelysdafaqj23ou89ZXcj@#$@#$#@KJdjklj;D../dSF.,
static com.shimeng.颜如玉.颜如玉QQ2693533893 破解死妈; => [0x200c72]: com.shimeng.颜如玉.颜如玉QQ2693533893@59ac573
static java.lang.String 诗梦MD5; => 9DDEB743E935CE399F1DFAF080775366

/* instance fields */
int B;
int L;
android.os.Handler hand2;
android.os.Handler hand3;
java.lang.Runnable runn2;
java.lang.Runnable runn3;
com.shimeng.qq2693533893.FloatViewUtil util;
android.view.View v;
java.lang.String 坐等前往世界的尽头的小船;
android.widget.TextView 解锁;

/* constructor methods */
void MyServiceOne();

/* static methods */
static java.lang.String SHA1(java.util.Map);
static void access$1000014(com.shimeng.qq2693533893.MyServiceOne);
static com.shimeng.qq2693533893.FloatViewUtil access$L1000000(com.shimeng.qq2693533893.MyServiceOne);
static boolean access$L1000002();
static java.lang.String access$L1000003();
static java.lang.String access$L1000004();
static android.os.Handler access$L1000018(com.shimeng.qq2693533893.MyServiceOne);
static android.os.Handler access$L1000021(com.shimeng.qq2693533893.MyServiceOne);
static java.lang.Runnable access$L1000023(com.shimeng.qq2693533893.MyServiceOne);
static void access$S1000000(com.shimeng.qq2693533893.MyServiceOne, com.shimeng.qq2693533893.FloatViewUtil);
static void access$S1000002(boolean);
static void access$S1000003(java.lang.String);
static void access$S1000004(java.lang.String);
static void access$S1000018(com.shimeng.qq2693533893.MyServiceOne, android.os.Handler);
static void access$S1000021(com.shimeng.qq2693533893.MyServiceOne, android.os.Handler);
static void access$S1000023(com.shimeng.qq2693533893.MyServiceOne, java.lang.Runnable);
static java.lang.String getOrderByLexicographic(java.util.Map);
static java.util.List getParamsName(java.util.Map);
static java.util.List lexicographicOrder(java.util.List);
static java.lang.String splitParams(java.util.List, java.util.Map);
static java.lang.String 颜如玉(java.lang.String);

/* instance methods */
android.os.IBinder onBind(android.content.Intent);
void onCreate();
void onDestroy();
void onRequestPermissionsResult(int, java.lang.String[], I[]);
java.lang.String smsOpera(java.lang.String);
java.lang.String 独自走在孤独的雨中(java.lang.String);
void 诗梦();
void sm();
void sm2();

}

发现程序一直在调用access$L1000018 ,查找该函数并查询调用情况如下。

android hooking watch class_method com.shimeng.qq2693533893.MyServiceOne.access$L1000018
com.shimeng.qq2693533893 on (Android: 6.0.1) [usb] # (agent) [1s0p2cg6mvi] Called com.shimeng.qq2693533893.MyServiceOne.access$L1000018(com.shimeng.qq2693533893.MyServiceOne)
(agent) [1s0p2cg6mvi] Backtrace:
com.shimeng.qq2693533893.MyServiceOne.access$L1000018(Native Method)
com.shimeng.qq2693533893.MyServiceOne$100000007.run(MyServiceOne.java:309)
android.os.Handler.handleCallback(Handler.java:739)
android.os.Handler.dispatchMessage(Handler.java:95)
android.os.Looper.loop(Looper.java:148)
android.app.ActivityThread.main(ActivityThread.java:5647)
java.lang.reflect.Method.invoke(Native Method)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635)

image-20230129092550240

hook该内部类并打印调用栈,发现调用栈上层反复调用com.shimeng.qq2693533893.MyServiceOne.access$100000007.run

同时在JEB中查看调用链,确实是在100000007中将音量调到最大,循环播放。

image-20230129085423767

class 100000007 implements Runnable {
private final MyServiceOne this$0;

static MyServiceOne access$0(100000007 arg4) {
return MyServiceOne.this;
}

@Override
public void run() {
MyServiceOne.this.hand2.postDelayed(this, 1800L);
AudioManager v1 = (AudioManager)MyServiceOne.this.getSystemService("audio");
v1.setStreamVolume(3, v1.getStreamMaxVolume(3), 4);
v1.getStreamMaxVolume(0);
v1.getStreamVolume(0);
v1.getStreamVolume(0);
((Vibrator)MyServiceOne.this.getApplication().getSystemService("vibrator")).vibrate(new long[]{100L, 1500L, 100L, 1500L}, -1);
}
}

一。AudioManager即音频管理器, 用于管理android系统各种音频类型 (包括系统声音,通话,铃声,音乐,闹铃)的音量设置。 还可以使用它来设置“耳机插入时”的广播接收器 (action:android.intent.action.MEDIABUTTON)。

二。MediaPlayer用于播放音频, android api中提供了该工具, 播放过程中可以控制音频的各种状态, 具体使用比较简单。 可以从资源文件中播放,从文件系统播放,从网络播放等方式。 具体包名:android.media.AudioManager

我们来hook该类,在循环调用该函数,调整声音大小。

com.shimeng.qq2693533893 on (Android: 6.0.1) [usb] # (agent) [kbvime5ddss] Called android.media.AudioManager.getStreamMaxVolume(int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getService()
(agent) [kbvime5ddss] Called android.media.AudioManager.setStreamVolume(int, int, int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getContext()
(agent) [kbvime5ddss] Called android.media.AudioManager.getContext()
(agent) [kbvime5ddss] Called android.media.AudioManager.getStreamMaxVolume(int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getService()
(agent) [kbvime5ddss] Called android.media.AudioManager.getStreamVolume(int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getService()
(agent) [kbvime5ddss] Called android.media.AudioManager.getStreamVolume(int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getService()
(agent) [kbvime5ddss] Called android.media.AudioManager.getStreamMaxVolume(int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getService()
(agent) [kbvime5ddss] Called android.media.AudioManager.setStreamVolume(int, int, int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getContext()
(agent) [kbvime5ddss] Called android.media.AudioManager.getContext()
(agent) [kbvime5ddss] Called android.media.AudioManager.getStreamMaxVolume(int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getService()
(agent) [kbvime5ddss] Called android.media.AudioManager.getStreamVolume(int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getService()
(agent) [kbvime5ddss] Called android.media.AudioManager.getStreamVolume(int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getService()
(agent) [kbvime5ddss] Called android.media.AudioManager.getStreamMaxVolume(int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getService()
(agent) [kbvime5ddss] Called android.media.AudioManager.setStreamVolume(int, int, int)
(agent) [kbvime5ddss] Called android.media.AudioManager.getContext()
(agent) [kbvime5ddss] Called android.media.AudioManager.getContext()

setStreamVolume (int streamType, int index, int flags) 。

函数具体使用如下。

setStreamVolume (int streamType, int index, int flags)  
第一个参数(需要调整音量的类型),可以是:
STREAM_ALARM 警报
STREAM_MUSIC 音乐回放即媒体音量
STREAM_NOTIFICATION 窗口顶部状态栏Notification
STREAM_RING 铃声
STREAM_SYSTEM 系统
STREAM_VOICE_CALL 通话
STREAM_DTMF 双音多频

第二个参数就是音量的int值

第三个参数是一些附加参数,常用有:
FLAG_PLAY_SOUND 调整音量时播放声音
FLAG_SHOW_UI 调整时显示音量条,就是按音量键出现的那个
0 表示什么也没有

//现在只需要hook android.media.AudioManager的setStreamVolume
//将此函数中的第二个参数置0即可
//hook 代码如下:
function hook_audio(){
Java.perform(function(){
console.log("Inside java perform");
Java.use("android.media.AudioManager").setStreamVolume.implementation = function(int1,int2,int3){
var res = this.setStreamVolume(int1,0,int3);
return res;
}
});
}

第一层

hook Called com.shimeng.qq2693533893.MyServiceOne后进行点击操作

(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.颜如玉(java.lang.String)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.SHA1(java.util.Map)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.getOrderByLexicographic(java.util.Map)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.getParamsName(java.util.Map)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.lexicographicOrder(java.util.List)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.splitParams(java.util.List, java.util.Map)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.颜如玉(java.lang.String)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.SHA1(java.util.Map)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.getOrderByLexicographic(java.util.Map)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.getParamsName(java.util.Map)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.lexicographicOrder(java.util.List)
(agent) [59xlexa5rds] Called com.shimeng.qq2693533893.MyServiceOne.splitParams(java.util.List, java.util.Map)

根据调用栈来分析对应函数,使用objection来hook com.shimeng.qq2693533893.MyServiceOne.颜如玉 函数,发现调用com.shimeng.qq2693533893.MyServiceOne$100000002.onClick(MyServiceOne.java:192) 函数,并打印出了对应的返回值

com.shimeng.qq2693533893 on (Android: 6.0.1) [usb] # android hooking watch class_method com.shimeng.qq2693533893.MyServiceOne.颜如玉 --dump-args --dump-backtrace --dump-return
(agent) Attempting to watch class com.shimeng.qq2693533893.MyServiceOne and method 颜如玉.
(agent) Hooking com.shimeng.qq2693533893.MyServiceOne.颜如玉(java.lang.String)
(agent) Registering job same6urlidq. Type: watch-method for: com.shimeng.qq2693533893.MyServiceOne.颜如玉
com.shimeng.qq2693533893 on (Android: 6.0.1) [usb] # (agent) [same6urlidq] Called com.shimeng.qq2693533893.MyServiceOne.颜如玉(java.lang.String)
(agent) [same6urlidq] Backtrace:
com.shimeng.qq2693533893.MyServiceOne.颜如玉(Native Method)
com.shimeng.qq2693533893.MyServiceOne$100000002.onClick(MyServiceOne.java:186)
android.view.View.performClick(View.java:5204)
android.view.View$PerformClick.run(View.java:21153)
android.os.Handler.handleCallback(Handler.java:739)
android.os.Handler.dispatchMessage(Handler.java:95)
android.os.Looper.loop(Looper.java:148)
android.app.ActivityThread.main(ActivityThread.java:5647)
java.lang.reflect.Method.invoke(Native Method)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635)

(agent) [same6urlidq] Arguments com.shimeng.qq2693533893.MyServiceOne.颜如玉(BDAFF3D900183B306F259885D923DF1C)
(agent) [same6urlidq] Return Value: 5948146256E1A341A6486442397EE2C2FB1A832E
(agent) [same6urlidq] Called com.shimeng.qq2693533893.MyServiceOne.颜如玉(java.lang.String)
(agent) [same6urlidq] Backtrace:
com.shimeng.qq2693533893.MyServiceOne.颜如玉(Native Method)
com.shimeng.qq2693533893.MyServiceOne$100000002.onClick(MyServiceOne.java:192)
android.view.View.performClick(View.java:5204)
android.view.View$PerformClick.run(View.java:21153)
android.os.Handler.handleCallback(Handler.java:739)
android.os.Handler.dispatchMessage(Handler.java:95)
android.os.Looper.loop(Looper.java:148)
android.app.ActivityThread.main(ActivityThread.java:5647)
java.lang.reflect.Method.invoke(Native Method)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635)

(agent) [same6urlidq] Arguments com.shimeng.qq2693533893.MyServiceOne.颜如玉(123)
(agent) [same6urlidq] Return Value: 84073A4AF62DB3D30C4BF2B31622CC0EB1FA9E70

定位到该函数。

    100000002(EditText arg16, int arg17, TextView arg18, Button arg19, TextView arg20, TextView arg21, TextView arg22, TextView arg23, TextView arg24) {
this.val$editText = arg16;
this.val$诗梦 = arg17;
this.val$lpo = arg18;
this.val$button = arg19;
this.val$textView2 = arg20;
this.val$a00 = arg21;
this.val$b00 = arg22;
this.val$c00 = arg23;
this.val$d00 = arg24;
}

static MyServiceOne access$0(100000002 arg4) {
return MyServiceOne.this;
}

@Override // android.view.View$OnClickListener
public void onClick(View arg15) {
String v2 = this.val$editText.getText().toString();
if(v2.length() >= 3) {
String v3 = MyServiceOne.颜如玉(颜如玉QQ2693533893.getSaltMD5("" + this.val$诗梦)).replaceAll("\\D+", "");
if(v3.length() > 9 && v3.length() > 3) {
if(颜如玉QQ2693533893.getSaltMD5(MyServiceOne.颜如玉(v2.substring(0, 3))) + v2.substring(3, v2.length()).equals("9DDEB743E935CE399F1DFAF080775366" + v3.substring(0, 9))) {
MyServiceOne.this.util.removeView();
MyServiceOne.this.sm2();
return;
}

--MyServiceOne.this.L;
++MyServiceOne.this.B;
this.val$lpo.setText("很抱歉!密码错误解锁请加QQ群:437732815联系管理员购买正确的密码解锁...密码以错" + MyServiceOne.this.B + "次!" + "还剩" + MyServiceOne.this.L + "次输入错误密码的机会");
if(MyServiceOne.this.L <= 0) {
this.val$lpo.setText("本次输入密码错误次数累计以达10次,请重启手机后获取输入密码机会!");
this.val$button.setVisibility(8);
this.val$textView2.setVisibility(8);
this.val$editText.setVisibility(8);
this.val$a00.setVisibility(8);
this.val$b00.setVisibility(8);
this.val$c00.setVisibility(8);
this.val$d00.setVisibility(8);
return;
}
}
}
}
}

可以看到重要逻辑部分在此处。

String v3 = MyServiceOne.颜如玉(颜如玉QQ2693533893.getSaltMD5("" + this.val$诗梦)).replaceAll("\\D+", "");

if(颜如玉QQ2693533893.getSaltMD5(MyServiceOne.颜如玉(v2.substring(0, 3))) + v2.substring(3, v2.length()).equals("9DDEB743E935CE399F1DFAF080775366" + v3.substring(0, 9))) {
MyServiceOne.this.util.removeView();
MyServiceOne.this.sm2();
return;
}

发现主要的判断逻辑如下,如果与9DDEB743E935CE399F1DFAF080775366相等,则移除MyServiceOne.this.util.removeView(),进入sm2

image-20230129102441093

在sm处获取对应的识别码。

private void sm() {
this.util = new FloatViewUtil(this);
this.v = LayoutInflater.from(this).inflate(0x7F030002, null); // layout:MT_Bin
this.util.setview(this.v);
this.util.createfloatview(-1, 0x500);
Button v3 = (Button)this.util.byid(0x7F07000B); // id:MT_Bin
TextView v4 = (TextView)this.util.byid(0x7F070008); // id:MT_Bin
EditText v5 = (EditText)this.util.byid(0x7F07000A); // id:MT_Bin
TextView v6 = (TextView)this.util.byid(0x7F07000F); // id:MT_Bin
TextView v7 = (TextView)this.util.byid(0x7F070007); // id:MT_Bin
TextView v8 = (TextView)this.util.byid(0x7F070009); // id:MT_Bin
TextView v9 = (TextView)this.util.byid(0x7F07000C); // id:MT_Bin
TextView v10 = (TextView)this.util.byid(0x7F07000D); // id:MT_Bin
int v11 = (int)(Math.random() * 4.879400E-320);
v4.setText("你的识别码=" + 颜如玉QQ2693533893.get("" + v11));
颜如玉QQ2693533893.te("sdcard");
USBLock v13 = new USBLock();
new Timer().schedule(v13, new Date(), 1000L);
v3.setOnClickListener(new 100000002(this, v5, v11 ^ 0x508, v6, v3, v4, v7, v8, v9, v10));

.get方法如下。

public static String get(String arg13) {
byte[] v1 = arg13.getBytes();
StringBuilder v2 = new StringBuilder(v1.length * 2);
int v3;
for(v3 = 0; v3 < v1.length; ++v3) {
v2.append(((char)颜如玉QQ2693533893.hexString.charAt((v1[v3] & 15) >> 0)));
}

String v3_1 = "";
String[] v4 = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
String[] v5 = {"嘻", "❥", "÷", "∷", "●", "©", "额", "★", "※", "/"};
int v6;
for(v6 = 0; v6 < 10; ++v6) {
if(v6 == 0) {
v3_1 = v2.toString().replace(v4[v6], v5[v6]);
}

v3_1 = v3_1.replace(v4[v6], v5[v6]);
}

return v3_1;
}

在sm()方法中拿到生成识别码的逻辑,跟进去原来是随机四位数做了火星文对应,在100000002构造函数中this.val$诗梦 = arg17;就是随机四位数v11 ^ 1288,,所以才显示在前台页面是火星文,那么我们可以通过hook颜如玉QQ2693533893.get()拿到四位数对应的该火星文,也可以直接根据V4 V5对应表来找到该火星文。

int v11 = (int)(Math.random() * 4.879400E-320);
v4.setText("你的识别码=" + 颜如玉QQ2693533893.get("" + v11));
颜如玉QQ2693533893.te("sdcard");
USBLock v13 = new USBLock();
new Timer().schedule(v13, new Date(), 1000L);
v3.setOnClickListener(new 100000002(this, v5, v11 ^ 0x508, v6, v3, v4, v7, v8, v9, v10));

可以根据get方法中对应的信息进行定位。

image-20230129103815123
String[] v4 = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
String[] v5 = {"嘻", "❥", "÷", "∷", "●", "©", "额", "★", "※", "/"};
6190

接着分析onClick方法可知随机四位数被作为参数给了getSaltMD5,那么我们可以通过反射和四位数拿到v3的值。

hook.js

function Find_Code(){
Java.perform(function(){
var javaString = Java.use('java.lang.String')

for(var i=999;i<10000;i++){
var i = javaString.$new(String(i));
var Code = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").get(i);
var v3 = Java.use("com.shimeng.qq2693533893.MyServiceOne").颜如玉(Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").getSaltMD5((javaString.$new(String(i^1288)))));
var v3 = javaString.$new(final_last9).replaceAll("\\D+", "");

console.log("i,Code,v3:",i,Code,v3);
if (Code == "额❥/嘻"){ // 5147
break;
}
}

})
}
i,Code,v3: 6179 额❥★/ 5930115214632905764947
i,Code,v3: 6180 额❥※嘻 107899719181495393421953265
i,Code,v3: 6181 额❥※❥ 637925064710567273601450494
i,Code,v3: 6182 额❥※÷ 79031009396005431455865545
i,Code,v3: 6183 额❥※∷ 927545851918403937793285270
i,Code,v3: 6184 额❥※● 1520178882327296987108
i,Code,v3: 6185 额❥※© 37660404572152154889
i,Code,v3: 6186 额❥※额 5153164879398001979082044
i,Code,v3: 6187 额❥※★ 7549072384256789855633
i,Code,v3: 6188 额❥※※ 04993536950983416668988739
i,Code,v3: 6189 额❥※/ 4503222936237929487161634306
i,Code,v3: 6190 额❥/嘻 91852619857657324187556049

接着我们分析判断的语句。

颜如玉QQ2693533893.getSaltMD5(MyServiceOne.颜如玉(v2.substring(0, 3))) + v2.substring(3, v2.length()).equals("9DDEB743E935CE399F1DFAF080775366" + v3.substring(0, 9))

//step1
getSaltMD5(MyServiceOne.颜如玉(v2.substring(0, 3))) + v2.substring(3, v2.length()) =
"9DDEB743E935CE399F1DFAF080775366" + v3.substring(0, 9)

//step2
getSaltMD5(MyServiceOne.颜如玉(v2.substring(0, 3))) = "9DDEB743E935CE399F1DFAF080775366"
v2.substring(3, v2.length() = v3.substring(0, 9)

hook1.js如下

for(var j=1;j<1000;j++){
var j = javaString.$new(String(j));
var v2_3 = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").getSaltMD5(Java.use("com.shimeng.qq2693533893.MyServiceOne").颜如玉(j));
// console.log("l, v2_3:",j,v2_3);
if(v2_3 == '9DDEB743E935CE399F1DFAF080775366'){
console.log("v2_3:",j);
}
}

// v2_3: 358

重新打开应用

image-20230129111427733
Code 7363

Hook1.js

function Find_Code(){
Java.perform(function(){
var javaString = Java.use('java.lang.String')
for(var j=1;j<1000;j++){
var j = javaString.$new(String(j));
var v2_3 = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").getSaltMD5(Java.use("com.shimeng.qq2693533893.MyServiceOne").颜如玉(j));
// console.log("l, v2_3:",j,v2_3);
if(v2_3 == '9DDEB743E935CE399F1DFAF080775366'){
console.log("v2_3:",j);
}
}

var i = javaString.$new(String(3744));
var Code = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").get(i);
var v3 = Java.use("com.shimeng.qq2693533893.MyServiceOne").颜如玉(Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").getSaltMD5((javaString.$new(String(i^1288)))));
var v3 = javaString.$new(v3).replaceAll("\\D+", "");
var resu1 = "358" + javaString.$new(v3).substring(0, 9);
console.log("i,Code,v3,resu1:",i,Code, v3, resu1);
})
}

结果为358230734399,输入进入第二层。

[Android Emulator 5554::com.shimeng.qq2693533893]-> Find_Code()
v2_3: 358
i,Code,v3,resu1: 7363 ★∷额∷ 2307343997321858474745697 358230734399

第二层

image-20230129123216805

整体逻辑和第一层一样,首先来看sm2函数。


this.util = new FloatViewUtil(this);
this.v = LayoutInflater.from(this).inflate(0x7F030001, null); // layout:MT_Bin
this.util.setview(this.v);
this.util.createfloatview(-1, 0x500);
Button v1 = (Button)this.util.byid(0x7F070006); // id:MT_Bin
TextView v2 = (TextView)this.util.byid(0x7F070004); // id:MT_Bin
EditText v3 = (EditText)this.util.byid(0x7F070005); // id:MT_Bin
int v4 = (int)(Math.random() * 4.940600E-319);
v2.setText("你的识别码=" + 颜如玉QQ2693533893.get("" + v4));
v1.setOnClickListener(new 100000003(this, v3, v4));
}

整体逻辑和sm1一样不过识别码变成了5位,关键代码如下。

if(v2.length() >= 3) {
String v3 = 颜如玉QQ2693533893.hex_sha1(MyServiceOne.破解死妈.getTwiceMD5ofString("" + this.val$u2)).replaceAll("\\D+", "");

if(v3.length() > 9 && v3.length() > 3 && (MyServiceOne.破解死妈.getTwiceMD5ofString(颜如玉QQ2693533893.hex_sha1(v2.substring(0, 3))) + v2.substring(3, v2.length()).equals("8D4FF507DCDA63C201EB8B99D4170900" + v3.substring(0, 9)))) {
MyServiceOne.this.util.removeView();
MyServiceOne.this.诗梦();
return;
}
}

根据第一层的规则直接编写脚本如下

hook2.js

function Find_Code(){
Java.perform(function(){
var javaString = Java.use('java.lang.String')
for(var j=1;j<1000;j++){
var j = javaString.$new(String(j));
var v2_3 = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").$new().getTwiceMD5ofString(Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").hex_sha1(j));
//console.log("l, v2_3:",j,v2_3);
if(v2_3 == '8D4FF507DCDA63C201EB8B99D4170900'){
console.log("v2_3:",j);
}
}



var i = javaString.$new(String(44207));
var Code = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").get(i);
var v3 = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").hex_sha1(Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").$new().getTwiceMD5ofString(i));
var v3 = javaString.$new(v3).replaceAll("\\D+", "");
var resu2 = "694" + javaString.$new(v3).substring(0, 9);
console.log("i,Code,v3,resu2",i,Code,v3,resu2)



})
}

运行结果:

[Android Emulator 5554::com.shimeng.qq2693533893]-> Find_Code()
v2_3: 694
i,Code,v3,resu1 44207 ●●÷嘻★ 98869461037719278110486 694988694610

第三层

image-20230129123346260

看关键代码,主要逻辑是访问一个网站获取密码,然后与输入的内容进行对比。

public void 诗梦() {
this.util = new FloatViewUtil(this);
this.v = LayoutInflater.from(this).inflate(0x7F030000, null); // layout:MT_Bin
this.util.setview(this.v);
this.util.createfloatview(-1, 0x500);
Button v1 = (Button)this.util.byid(0x7F070001); // id:MT_Bin
EditText v2 = (EditText)this.util.byid(0x7F070000); // id:MT_Bin
this.解锁 = (TextView)this.util.byid(0x7F070002); // id:MT_Bin
v1.setOnClickListener(new 100000006(this, v2));
}
class 100000006 implements View.OnClickListener {
class 100000004 implements Runnable {
private final 100000006 this$0;

static 100000006 access$0(100000004 arg4) {
return 100000006.this;
}

@Override
public void run() {
try {
String v1 = 100000006.access$0(100000006.this).独自走在孤独的雨中("https://www.lanzous.com/b819183");
100000006.access$0(100000006.this).坐等前往世界的尽头的小船 = v1.substring(v1.indexOf("【"), v1.indexOf("】")).replace("【", "");
}
catch(Exception v3) {
}
}
}

public void onClick(View arg12) {
new Thread(new 100000004(this)).start();
if("187724addd757b99a9dc1eb570c65f32c33f5941".equals(MyServiceOne.this.坐等前往世界的尽头的小船)) {
MyServiceOne.this.util.removeView();
new Timer().schedule(new 100000005(this), 1500L);
return;
}

if(颜如玉QQ2693533893.hex_sha1(this.val$fuck.getText().toString()).equals(MyServiceOne.this.坐等前往世界的尽头的小船)) {
MyServiceOne.this.util.removeView();
return;
}

MyServiceOne.this.解锁.setVisibility(0);
MyServiceOne.this.解锁.setText("密码错误,手机恢复正常失败/nManifest-Version: 1.0Created-By: 1.0 (Android SignApk)");
Runnable v6 = MyServiceOne.this.runn3;
MyServiceOne.this.hand3.postDelayed(v6, 2000L);
}
}

网盘链接已经失效,我们编写脚本给内存中变量v0.this$0.坐等前往世界的尽头的小船赋值即可解锁。

function Find_Code(){
Java.perform(function(){
console.log("Inside java perform");
var val = "123123";
var string_class = Java.use("java.lang.String");
var flag = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").hex_sha1(string_class.$new(val));
Java.choose("com.shimeng.qq2693533893.MyServiceOne",{
onMatch:function(instance){
instance.坐等前往世界的尽头的小船.value = flag;
},onComplete:function(){console.log("flag,value",flag,val);}
})
});
}
[Android Emulator 5554::com.shimeng.qq2693533893]-> Find_Code3()
Inside java perform
flag,value 601f1889667efaebb33b8c12572835da3f027f78 123123

输入123123 即可解锁

image-20230129125736432

完整脚本

hook.js

// String[] v4 = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
// String[] v5 = {"嘻", "❥", "÷", "∷", "●", "©", "额", "★", "※", "/"};
function Find_Code1(){
Java.perform(function(){
var javaString = Java.use('java.lang.String')
for(var j=1;j<1000;j++){
var j = javaString.$new(String(j));
var v2_3 = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").getSaltMD5(Java.use("com.shimeng.qq2693533893.MyServiceOne").颜如玉(j));
// console.log("l, v2_3:",j,v2_3);
if(v2_3 == '9DDEB743E935CE399F1DFAF080775366'){
console.log("v2_3:",j);
}
}

var i = javaString.$new(String(3744));
var Code = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").get(i);
var v3 = Java.use("com.shimeng.qq2693533893.MyServiceOne").颜如玉(Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").getSaltMD5((javaString.$new(String(i^1288)))));
var v3 = javaString.$new(v3).replaceAll("\\D+", "");
var resu1 = "358" + javaString.$new(v3).substring(0, 9);
console.log("i,Code,v3,resu1:",i,Code, v3, resu1);
})
}
function Find_Code2(){
Java.perform(function(){
var javaString = Java.use('java.lang.String')
for(var j=1;j<1000;j++){
var j = javaString.$new(String(j));
var v2_3 = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").$new().getTwiceMD5ofString(Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").hex_sha1(j));
//console.log("l, v2_3:",j,v2_3);
if(v2_3 == '8D4FF507DCDA63C201EB8B99D4170900'){
console.log("v2_3:",j);
}
}
var i = javaString.$new(String(694));
var Code = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").get(i);
var v3 = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").hex_sha1(Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").$new().getTwiceMD5ofString(i));
var v3 = javaString.$new(v3).replaceAll("\\D+", "");
var resu2 = "694" + javaString.$new(v3).substring(0, 9);
console.log("i,Code,v3,resu2",i,Code,v3,resu2)



})
}
function Find_Code3(){
Java.perform(function(){
console.log("Inside java perform");
var val = "123123";
var string_class = Java.use("java.lang.String");
var flag = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").hex_sha1(string_class.$new(val));
Java.choose("com.shimeng.qq2693533893.MyServiceOne",{
onMatch:function(instance){
instance.坐等前往世界的尽头的小船.value = flag;
},onComplete:function(){console.log("flag,value",flag,val);}
})
});
}
Author

ol4three

Posted on

2022-04-12

Updated on

2023-01-29

Licensed under


Comments