通过一个app来看Frida检测

  1. sub_1c544
    1. sub_1bfac
    2. sub_1c158
    3. sub_1c26c
  2. sub_1b8d4
    1. sub_1ae48
    2. sub_1ab54
    3. sub_1b730
  3. sub_26e5c
    1. sub_1678c
  4. 总结

尝试hook

1

可以看到frida启动后一会就被kill了,手机上的app也退出了

现在需要找到检测点,首先通过hook dlopen看看是在哪一个so中退出的

2

libmsaoaidsec.so中,那么具体的检测函数如何定位呢,frida的检测函数很有可能会调用pthread_create来创建检测线程,那么我们可以尝试去hook一下这个函数

但是hook的时机很重要,linker在加载so时会按顺序执行:.init,.init_array,JNI_OnLoad

.init,.init_array是在do_dlopen中执行的,find_library函数会根据命名空间ns,库名translate_name,加载标志flags,拓展信息extinfo和调用者caller来查找库,si指向找到的库。call_constructors函数负责调用库中的.init段和.init_array段中的函数。

1
2
3
soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
...
si->call_constructors();

3

先看看在不在JNI_OnLoad中,

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
function hook_dlopen(){
Java.perform(function(){
var dlopen = Module.findExportByName(null, "dlopen");
var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");

Interceptor.attach(dlopen, {
onEnter: function (args) {
var path_ptr = args[0];
var path = ptr(path_ptr).readCString();
console.log("[dlopen:]", path);
},
onLeave: function (retval) {

}
});
Interceptor.attach(android_dlopen_ext, {
onEnter: function (args) {
var path_ptr = args[0];
var path = ptr(path_ptr).readCString();
console.log("[dlopen_ext:]", path);
},
onLeave: function (retval) {
if(this.fileName!=null && this.fileName.indexOf("libmsaoaidsec.so")>=0){
let JNI_OnLoad = Module.findExportByName(this.fileName, "JNI_OnLoad")
console.log("[*] JNI_Onload " + JNI_OnLoad);
}
}
});
})
}

hook后发现并没有JNI_OnLoad字眼,那么检测就在JNI_OnLoad之前,hook的时机选择上面提到的call_constructors,hook thread_create。

1
2
3
4
//获取call_constructors的偏移
C:\Users\n1ng>adb shell
cepheus:/ $ readelf -sW /apex/com.android.runtime/bin/linker64 | grep call_constructors
715: 000000000004b140 556 FUNC LOCAL HIDDEN 11 __dl__ZN6soinfo17call_constructorsEv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function hook_linker_call_constructors() {
let linker64_base_addr = Module.getBaseAddress('linker64')
let offset = 0x4b140 // __dl__ZN6soinfo17call_constructorsEv
let call_constructors = linker64_base_addr.add(offset)
let listener = Interceptor.attach(call_constructors,{
onEnter:function(args){
console.log('hook_linker_call_constructors onEnter')
let secmodule = Process.findModuleByName("libmsaoaidsec.so")
if (secmodule != null){
// do something
hook_pthred_create();
}
}
})
}
function hook_pthred_create(){
console.log("[*] libmaoaidsec.so "+ Process.findModuleByName("libmsaoaidsec.so").base)
Interceptor.attach(Module.findExportByName('libc.so','pthread_create'),{
onEnter(args){
let func_addr = args[2]
console.log(`The thread Called function address is: ${func_addr}`)
}
})
}

hook结果

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
hook_linker_call_constructors onEnter
[*] libmaoaidsec.so 0x6ed6140000
The thread Called function address is: 0x6ed615c544
The thread Called function address is: 0x6ed615c544
The thread Called function address is: 0x6ed615c544
The thread Called function address is: 0x6ed615c544
The thread Called function address is: 0x6ed615c544
The thread Called function address is: 0x6ed615c544
The thread Called function address is: 0x6ed615c544
The thread Called function address is: 0x6ed615c544
The thread Called function address is: 0x6ed615b8d4
The thread Called function address is: 0x6ed615b8d4
The thread Called function address is: 0x6ed615b8d4
The thread Called function address is: 0x6ed615b8d4
The thread Called function address is: 0x6ed615b8d4
The thread Called function address is: 0x6ed615b8d4
The thread Called function address is: 0x6ed615b8d4
The thread Called function address is: 0x6ed615b8d4
hook_linker_call_constructors onEnter
[*] libmaoaidsec.so 0x6ed6140000
The thread Called function address is: 0x6ed6166e5c
The thread Called function address is: 0x6ed6166e5c
The thread Called function address is: 0x6ed6166e5c
The thread Called function address is: 0x6ed6166e5c
The thread Called function address is: 0x6ed6166e5c
The thread Called function address is: 0x6ed6166e5c
The thread Called function address is: 0x6ed6166e5c
The thread Called function address is: 0x6ed6166e5c
The thread Called function address is: 0x6ed6166e5c
Process terminated
[MI 9::com.shizhuang.duapp ]->

计算一下偏移

1
2
3
4
5
6
>>> data = [0x6ed615c544,0x6ed615b8d4,0x6ed6166e5c]
>>> k = 0x6ed6140000
>>> for i in data:
... print(hex(i - k),end = ',')
...
0x1c544,0x1b8d4,0x26e5c

sub_1c544

ida中跳到1c544看看

4

byte_49030,byte_4904A,byte_49056并不是有意思的字符,并且前面有一些异或的操作,猜测就是对字符做了加密

hook然后dump一下看

1
2
3
4
5
6
function hook_so(){
var base_addr = Module.findBaseAddress("libmsaoaidsec.so");
var dump_addr = base_addr.add(0x49020);
console.log(hexdump(dump_addr, {length: 0x8f}));
}

1
2
3
4
5
6
7
8
9
10
             0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F  0123456789ABCDEF
6ec2d91020 2f 70 72 6f 63 2f 73 65 6c 66 2f 74 61 73 6b 00 /proc/self/task.
6ec2d91030 2f 70 72 6f 63 2f 73 65 6c 66 2f 74 61 73 6b 2f /proc/self/task/
6ec2d91040 25 73 2f 73 74 61 74 75 73 00 67 75 6d 2d 6a 73 %s/status.gum-js
6ec2d91050 2d 6c 6f 6f 70 00 67 6d 61 69 6e 00 2f 70 72 6f -loop.gmain./pro
6ec2d91060 63 2f 73 65 6c 66 2f 66 64 00 6c 69 6e 6a 65 63 c/self/fd.linjec
6ec2d91070 74 6f 72 00 2f 70 72 6f 63 2f 73 65 6c 66 2f 6d tor./proc/self/m
6ec2d91080 61 70 73 00 2f 64 61 74 61 2f 6c 6f 63 61 6c 2f aps./data/local/
6ec2d91090 74 6d 70 00 5f 41 47 45 4e 54 5f 31 2e 30 00 66 tmp._AGENT_1.0.f
6ec2d910a0 72 69 64 61 2d 61 67 65 6e 74 00 00 00 00 00 rida-agent.....

可以看到就是对一些常见检测中会用到的字符

  • /proc/self/task,查看线程信息,frida注入后会多出几个线程
  • gum-js-loop,特征字符
  • gmain,特征字符
  • /proc/self/fd,检测文件描述符信息
  • injector,特征字符
  • /proc/self/maps,frida注入后会在maps中显示一些包含特征字符的信息
  • /data/local/tmp,比较敏感的一个路径
  • _AGENT_1.0,特征字符
  • frida-agent,特征字符

但这里还没有做具体的检测。看到了几个可疑函数,跟过去看看

sub_1bfac

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
51
52
53
54
55
56
57
58
59
DIR *sub_1BFAC()
{
DIR *result; // x0
DIR *v1; // x19
struct dirent *v2; // x0
struct dirent *v3; // x25
const char *d_name; // x25
int v5; // w0
unsigned int v6; // w25
unsigned __int64 i; // x29
char v8[4]; // [xsp+14h] [xbp-46Ch] BYREF
char haystack[512]; // [xsp+18h] [xbp-468h] BYREF
char s[520]; // [xsp+218h] [xbp-268h] BYREF

_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
result = opendir(byte_49020);
if ( result )
{
v1 = result;
v2 = readdir(result);
if ( v2 )
{
v3 = v2;
do
{
memset(s, 0, 0x200u);
d_name = v3->d_name;
if ( strcmp(d_name, byte_305E5) )
{
if ( strcmp(d_name, &byte_305E4) )
{
_snprintf_chk(s, 512LL, 0LL, 512LL, byte_49030, d_name);
v5 = openat(-100, s, 0x80000, 0LL);
if ( v5 )
{
v6 = v5;
memset(haystack, 0, sizeof(haystack));
for ( i = 0LL; i < 0x1FF; ++i )
{
if ( _read_chk(v6, v8, 1LL, 1LL) != 1 )
break;
if ( v8[0] == 10 )
break;
haystack[i] = v8[0];
}
if ( strstr(haystack, byte_4904A) || strstr(haystack, byte_49056) )
exit(0);
close(v6);
}
}
}
v3 = readdir(v1);
}
while ( v3 );
}
return (DIR *)closedir(v1);
}
return result;
}

,继续往下跟到sub_1BFAC

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
51
52
53
54
55
56
57
58
59
DIR *sub_1BFAC()
{
DIR *result; // x0
DIR *v1; // x19
struct dirent *v2; // x0
struct dirent *v3; // x25
const char *d_name; // x25
int v5; // w0
unsigned int v6; // w25
unsigned __int64 i; // x29
char v8[4]; // [xsp+14h] [xbp-46Ch] BYREF
char haystack[512]; // [xsp+18h] [xbp-468h] BYREF
char s[520]; // [xsp+218h] [xbp-268h] BYREF

_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
result = opendir(byte_49020);
if ( result )
{
v1 = result;
v2 = readdir(result);
if ( v2 )
{
v3 = v2;
do
{
memset(s, 0, 0x200u);
d_name = v3->d_name;
if ( strcmp(d_name, byte_305E5) )
{
if ( strcmp(d_name, &byte_305E4) )
{
_snprintf_chk(s, 512LL, 0LL, 512LL, byte_49030, d_name);
v5 = openat(-100, s, 0x80000, 0LL);
if ( v5 )
{
v6 = v5;
memset(haystack, 0, sizeof(haystack));
for ( i = 0LL; i < 0x1FF; ++i )
{
if ( _read_chk(v6, v8, 1LL, 1LL) != 1 )
break;
if ( v8[0] == 10 )
break;
haystack[i] = v8[0];
}
if ( strstr(haystack, byte_4904A) || strstr(haystack, byte_49056) )
exit(0);
close(v6);
}
}
}
v3 = readdir(v1);
}
while ( v3 );
}
return (DIR *)closedir(v1);
}
return result;
}

result = opendir(byte_49020);这里就是open了/proc/self/task

strcmp(d_name, byte_305E5),即和”/proc/self/fd/%s”比较

这里即openat /proc/self/task/%s/status,”/proc/self/fd/%s”

1
2
_snprintf_chk(s, 512LL, 0LL, 512LL, byte_49030, d_name);
v5 = openat(-100, s, 0x80000, 0LL);

就是检测线程名和fd有没有”gum-js-loop”或”gmain”特征字符

1
strstr(haystack, byte_4904A) || strstr(haystack, byte_49056)

sub_1c158

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
DIR *sub_1C158()
{
DIR *result; // x0
DIR *v1; // x19
struct dirent *v2; // x0
struct dirent *v3; // x22
char v4[16]; // [xsp+8h] [xbp-4C8h] BYREF
int v5; // [xsp+18h] [xbp-4B8h]
char file[512]; // [xsp+88h] [xbp-448h] BYREF
char s[512]; // [xsp+288h] [xbp-248h] BYREF
__int64 v8; // [xsp+488h] [xbp-48h]

v8 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
result = opendir(byte_4905C);
if ( result )
{
v1 = result;
v2 = readdir(result);
if ( v2 )
{
v3 = v2;
do
{
memset(s, 0, sizeof(s));
memset(file, 0, sizeof(file));
_snprintf_chk(file, 512LL, 0LL, 512LL, "/proc/self/fd/%s", v3->d_name);
lstat(file, (struct stat *)v4);
if ( (v5 & 0xF000) == 40960 )
{
readlink(file, s, 0x200u);
if ( strstr(s, byte_4906A) )
exit(0);
}
v3 = readdir(v1);
}
while ( v3 );
}
return (DIR *)closedir(v1);
}
return result;
}

这里就是获取fd,对特征字符”Injector”的判断

sub_1c26c

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
__int64 sub_1C26C()
{
...
...

v29 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
v18 = 0LL;
v19 = 0LL;
v21 = &v18;
v22 = 0LL;
v20 = &v18;
v0 = fopen(byte_49074, "r");
if ( v0 )
{
v1 = v0;
v27 = 0;
v26 = 0LL;
v25 = 0;
v24 = 0LL;
memset(s, 0, sizeof(s));
if ( !feof(v1) )
{
v2 = off_47FC8;
do
{
if ( !fgets(v28, 4096, v1) )
break;
if ( sscanf(v28, "%lx-%lx %s %lx %s %ld %s", &v16, &v15, &v26, &v13, &v24, &v14, s) == 7 )
{
if ( strstr(s, byte_49084) )
{
if ( strchr((const char *)&v26, 120) )
{
if ( strchr((const char *)&v26, 114) )
{
sub_28258((int)&v12, s);
std::_Rb_tree<std::string,std::string,std::_Identity<std::string>,std::less<std::string>,std::allocator<std::string>>::_M_insert_unique<std::string>(
v17,
&v12);
v3 = (void *)(v12 - 24);
if ( (void *)(v12 - 24) != v2 )
{
v4 = (unsigned int *)(v12 - 8);
do
v5 = __ldaxr(v4);
while ( __stlxr(v5 - 1, v4) );
if ( v5 <= 0 )
j_operator delete(v3);
}
}
}
}
}
}
while ( !feof(v1) );
}
fclose(v1);
}
v6 = v20;
if ( v20 == &v18 )
{
LABEL_22:
std::_Rb_tree<std::string,std::string,std::_Identity<std::string>,std::less<std::string>,std::allocator<std::string>>::_M_erase(
v17,
v19);
v10 = 0LL;
v19 = 0LL;
v20 = &v18;
v21 = &v18;
v22 = 0LL;
}
else
{
while ( 1 )
{
v7 = operator new(0x158uLL);
*(_OWORD *)(v7 + 184) = 0u;
*(_OWORD *)(v7 + 168) = 0u;
*(_OWORD *)(v7 + 152) = 0u;
*(_OWORD *)(v7 + 136) = 0u;
*(_OWORD *)(v7 + 120) = 0u;
*(_BYTE *)(v7 + 200) = 0;
*(_OWORD *)(v7 + 56) = 0u;
*(_OWORD *)(v7 + 40) = 0u;
*(_OWORD *)(v7 + 24) = 0u;
*(_OWORD *)(v7 + 8) = 0u;
*(_QWORD *)v7 = 0LL;
*(_OWORD *)(v7 + 304) = 0u;
*(_OWORD *)(v7 + 320) = 0u;
*(_OWORD *)(v7 + 272) = 0u;
*(_OWORD *)(v7 + 288) = 0u;
*(_OWORD *)(v7 + 240) = 0u;
*(_OWORD *)(v7 + 256) = 0u;
*(_OWORD *)(v7 + 208) = 0u;
*(_OWORD *)(v7 + 224) = 0u;
v8 = (char *)v6[4];
v9 = (_QWORD *)v7;
*(_QWORD *)(v7 + 336) = 0LL;
if ( (sub_18774(v7, v8) & 1) == 0 || (sub_18240(v9 + 3, *v9) & 1) == 0 )
break;
if ( (sub_1806C((int)v9 + 24, (int)byte_49094, byte_4909F) & 1) != 0 )
exit(0);
sub_18F0C(v9);
operator delete(v9);
v6 = (__int64 *)sub_27B04(v6);
if ( v6 == &v18 )
goto LABEL_22;
}
sub_18F0C(v9);
operator delete(v9);
v10 = v19;
}
return std::_Rb_tree<std::string,std::string,std::_Identity<std::string>,std::less<std::string>,std::allocator<std::string>>::_M_erase(
v17,
v10);
}

sscanf(v28, “%lx-%lx %s %lx %s %ld %s”, &v16, &v15, &v26, &v13, &v24, &v14, s) == 7这里是open了maps文件,

/proc/self/maps 是一个特殊的文件,它包含了当前进程的内存映射信息。当你打开这个文件时,它会显示一个列表,其中包含了进程中每个内存区域的详细信息。这些信息通常包括:

  • 起始地址(Start Address)
  • 结束地址(End Address)
  • 权限(如可读、可写、可执行)
  • 共享/私有标志(Shared or Private)
  • 关联的文件或设备(如果内存区域是文件映射的)
  • 内存区域的偏移量
  • 内存区域的类型(如匿名映射、文件映射、设备映射等)
    当注入frida后,在maps文件中就会存在 frida-agent-64.sofrida-agent-32.so 等文件。

七个字段值依次为:内存区域(start和end)–权限–文件在内存中的偏移量–设备号–文件索引节点–路径

检测了路径是否在/data/local/tmp目录,是否是可读可执行的程序,以及”frida-agent”特征字符

sub_1b8d4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void __noreturn sub_1B8D4()
{
unsigned int v0; // w0
__useconds_t v1; // w19
unsigned int v2; // w0

v0 = sub_CB28();
if ( v0 >= 0x64 )
v1 = v0;
else
v1 = 2000000;
while ( 1 )
{
v2 = sub_1AE48();
if ( v2 == -1 || v2 && ((unsigned int)sub_1AB54(v2) & 1) == 0 || (unsigned int)sub_1B730() == 777 )
sub_11FA4();
usleep(v1);
}
}

sub_1ae48

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
__int64 sub_1AE48()
{
...
...

v32 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
memset(s, 0, sizeof(s));
*(_OWORD *)v30 = xmmword_304DF;
v0 = _strlen_chk(v30, 0x10u);
if ( (int)v0 >= 1 )
{
if ( v0 < 2uLL )
{
v1 = 0LL;
LABEL_7:
v7 = v0 - v1;
v8 = &v30[v1];
do
{
v9 = dword_305BC[(unsigned int)v1 % 3];
--v7;
LODWORD(v1) = v1 + 1;
*v8++ ^= v9;
}
while ( v7 );
goto LABEL_9;
}
v1 = v0 - (unsigned __int64)(v0 & 1);
v2 = 0;
v3 = 1;
v4 = &v30[1];
v5 = v1;
do
{
v6 = dword_305BC[v3 % 3];
v5 -= 2LL;
v3 += 2;
LOBYTE(v6) = *v4 ^ v6;
*(v4 - 1) ^= LOBYTE(dword_305BC[v2 % 3]);
*v4 = v6;
v4 += 2;
v2 += 2;
}
while ( v5 );
if ( (v0 & 1) != 0 )
goto LABEL_7;
}
LABEL_9:
_sprintf_chk(s, 0LL, 1024LL, v30, (unsigned int)dword_49014);
v10 = fopen(s, "r");
if ( v10 )
{
v11 = v10;
memset(haystack, 0, sizeof(haystack));
v28 = 0;
v27 = 0xA3CD;
v26 = 0xCEC9DBC2FAC8D5CDLL;
v12 = _strlen_chk((const char *)&v26, 0xBu);
if ( (int)v12 < 1 )
goto LABEL_19;
if ( v12 < 2uLL )
{
v13 = 0LL;
LABEL_17:
v20 = v12 - v13;
v21 = (char *)&v26 + v13;
do
{
v22 = dword_305BC[(unsigned int)v13 % 3];
--v20;
LODWORD(v13) = v13 + 1;
*v21++ ^= v22;
}
while ( v20 );
goto LABEL_19;
}
v13 = v12 - (unsigned __int64)(v12 & 1);
v15 = 0;
v16 = 1;
v17 = (char *)&v26 + 1;
v18 = v13;
do
{
v19 = dword_305BC[v16 % 3];
v18 -= 2LL;
v16 += 2;
LOBYTE(v19) = *v17 ^ v19;
*(v17 - 1) ^= LOBYTE(dword_305BC[v15 % 3]);
*v17 = v19;
v17 += 2;
v15 += 2;
}
while ( v18 );
if ( (v12 & 1) != 0 )
goto LABEL_17;
LABEL_19:
while ( fgets(haystack, 1024, v11) )
{
v23 = strstr(haystack, (const char *)&v26);
if ( v23 )
{
v24 = atoi(v23 + 10);
if ( v24 )
{
v14 = v24;
fclose(v11);
return v14;
}
break;
}
}
fclose(v11);
return 0;
}
else
{
return (unsigned int)-1;
}
}

这里就是获取进程信息,看TracePid的值(如果TracePid的值为0说明正在被调试)

sub_1ab54

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
FILE *__fastcall sub_1AB54(unsigned int a1)
{
...
...

v30 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
memset(s, 0, sizeof(s));
*(_OWORD *)v28 = xmmword_304DF;
if ( a1 == -1 )
return 0LL;
v2 = _strlen_chk(v28, 0x10u);
if ( (int)v2 >= 1 )
{
if ( v2 >= 2uLL )
{
v3 = v2 - (unsigned __int64)(v2 & 1);
v4 = 0;
v5 = 1;
v6 = &v28[1];
v7 = v3;
do
{
v8 = dword_305BC[v5 % 3];
v7 -= 2LL;
v5 += 2;
LOBYTE(v8) = *v6 ^ v8;
*(v6 - 1) ^= LOBYTE(dword_305BC[v4 % 3]);
*v6 = v8;
v6 += 2;
v4 += 2;
}
while ( v7 );
if ( (v2 & 1) == 0 )
goto LABEL_10;
}
else
{
v3 = 0LL;
}
v9 = v2 - v3;
v10 = &v28[v3];
do
{
v11 = dword_305BC[(unsigned int)v3 % 3];
--v9;
LODWORD(v3) = v3 + 1;
*v10++ ^= v11;
}
while ( v9 );
}
LABEL_10:
_sprintf_chk(s, 0LL, 1024LL, v28, a1);
result = fopen(s, "r");
if ( !result )
return result;
v13 = result;
memset(haystack, 0, sizeof(haystack));
v26 = 157;
*(_DWORD *)needle = 0xFDC0F7C9;
v14 = _strlen_chk(needle, 6u);
if ( (int)v14 < 1 )
goto LABEL_19;
if ( v14 < 2uLL )
{
v15 = 0LL;
LABEL_17:
v21 = v14 - v15;
v22 = &needle[v15];
do
{
v23 = dword_305BC[(unsigned int)v15 % 3];
--v21;
LODWORD(v15) = v15 + 1;
*v22++ ^= v23;
}
while ( v21 );
goto LABEL_19;
}
v15 = v14 - (unsigned __int64)(v14 & 1);
v16 = 0;
v17 = 1;
v18 = &needle[1];
v19 = v15;
do
{
v20 = dword_305BC[v17 % 3];
v19 -= 2LL;
v17 += 2;
LOBYTE(v20) = *v18 ^ v20;
*(v18 - 1) ^= LOBYTE(dword_305BC[v16 % 3]);
*v18 = v20;
v18 += 2;
v16 += 2;
}
while ( v19 );
if ( (v14 & 1) != 0 )
goto LABEL_17;
do
{
LABEL_19:
if ( !fgets(haystack, 1024, v13) )
goto LABEL_22;
v24 = strstr(haystack, needle);
}
while ( !v24 );
if ( atoi(v24 + 5) == dword_49014 )
{
LABEL_22:
fclose(v13);
return (FILE *)(&byte_0 + 1);
}
fclose(v13);
return 0LL;
}

这里就是打开了获取status,PPid

sub_1b730

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
51
52
53
54
55
56
57
58
59
60
61
62
__int64 sub_1B730()
{
...
...

v16 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
memset(s, 0, sizeof(s));
memset(name, 0, sizeof(name));
memset(v13, 0, sizeof(v13));
v0 = getpid();
_sprintf_chk(name, 0LL, 1024LL, "/proc/%d/task", v0);
v1 = opendir(name);
if ( !v1 )
return 0xFFFFFFFFLL;
v2 = v1;
v3 = readdir(v1);
if ( v3 )
{
while ( 1 )
{
d_name = v3->d_name;
v4 = v3->d_name[0];
if ( v4 )
{
v6 = &v3->d_name[1];
while ( (unsigned int)v4 - 48 > 9 )
{
v7 = (unsigned __int8)*v6++;
v4 = v7;
if ( !v7 )
goto LABEL_14;
}
v8 = getpid();
_sprintf_chk(s, 0LL, 512LL, "/proc/%d/task/%s/stat", v8, d_name);
result = open(s, 0);
if ( (_DWORD)result == -1 )
return result;
v10 = result;
result = _read_chk(result, v13, 1024LL, 1024LL);
if ( result == -1 )
return result;
v11 = 0LL;
do
v12 = (unsigned __int8)v13[v11++];
while ( v12 != 0x29 );
close(v10);
if ( ((unsigned __int8)v13[(unsigned int)(v11 + 1)] | 0x20) == 't' && v13[(unsigned int)(v11 + 2)] == ' ' )
return 777LL;
}
LABEL_14:
v3 = readdir(v2);
if ( !v3 )
goto LABEL_15;
}
}
else
{
LABEL_15:
closedir(v2);
return 0LL;
}
}

就是获取线程信息然后看线程的状态是否为”t”。在 /proc 文件系统中,进程和线程的状态字符通常有以下几种常见的表示:

  • R: 运行 (running or runnable)
  • S: 睡眠 (interruptible sleep)
  • D: 不可中断的睡眠 (uninterruptible sleep)
  • T: 停止 (stopped)
  • Z: 僵尸 (zombie)
  • X: 退出 (dead)

sub_26e5c

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
__int64 sub_26E5C()
{
unsigned int v0; // w0
int v1; // w8
unsigned int v3; // [xsp+10h] [xbp-70h]
bool v4; // [xsp+16h] [xbp-6Ah]
bool v5; // [xsp+17h] [xbp-69h]

_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2));
v0 = sub_C930();
v1 = -1782206741;
v3 = v0;
while ( 1 )
{
while ( 1 )
{
while ( v1 > -1137393265 )
{
if ( v1 > -499842569 )
{
if ( v1 == -499842568 )
{
if ( (sub_1678C() & 1) != 0 )
v1 = -1150116660;
else
v1 = -1827189700;
}
else
{
v5 = v3 != 0;
v1 = -1137393264;
}
}
else if ( v1 == -1137393264 )
{
if ( v4 && v5 )
v1 = -499842568;
else
v1 = -1150116660;
}
else
{
v1 = -1372371036;
}
}
if ( v1 > -1372371037 )
break;
if ( v1 == -1827189700 )
{
sub_269AC(0LL);
v1 = -1150116660;
}
else
{
v1 = -779687515;
}
}
if ( v1 != -1372371036 )
break;
v4 = v3 < 0xD;
v1 = 629336195;
}
return 0LL;
}

sub_1678c

这函数比较长有一千多行,这里就不放了

看了下有

获取/proc/%d/cmdline,获取maps信息,判断是否加载了libmsaoaidsec.so

对Android SDK版本获取,获取META-INF/CERT.RSA,META-INF/ANDROID.RSA,后面也看到一些和rsa有关的数字,这里可能是在做签名检测之类的?

总结

这样看来似乎就是一些特征字符的检测,那么我们试着用hluda等魔改的frida来hook,发现就不会退出了


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 3049155267@qq.com

💰

×

Help us with donation