0%

Android-内联SVC指令

应用场景

对抗各种基于 libc.so 的 Hook.

方式一:静态链接 libc.a

把 libc 以静态库的方式内联到可执行文件或 so 库。从而不调用系统 libc.so 库的函数

代码

main.cpp

1
2
3
4
5
6
#include <unistd.h>

int main(int argc, char *argv[])
{
sleep(20);
}

Android.bp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cc_binary {
name: "testLibc",
srcs: ["*.cpp"],

cppflags: [
"-Wno-error",
"-Wno-sign-conversion",
"-Wno-unused-parameter",
"-Wno-sign-conversion",
],

static_executable: true,

static_libs: [
"libc",
],

}

编译

1
2
3
4
source build/envsetup.sh
lunch 2
cd external/testLibc
mm

效果

将编译后的文件用 ida 打开,观察其导入函数.

发现是空的,说明 sleep 函数已经被内联.
丢到真机执行,

20 秒后退出,也没啥问题.

测试用例:
https://github.com/PShocker/PShocker.github.io/releases/download/testLibc/testLibc

方式二:汇编方式内联 SVC 指令

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
#define SYSCALL(number_, nb_args, args...)			\
({ \
register word_t number asm("r7") = number_; \
register word_t result asm("r0"); \
PREPARE_ARGS_##nb_args(args) \
asm volatile ( \
"svc #0x00000000 \n\t" \
: "=r" (result) \
: "r" (number), \
OUTPUT_CONTRAINTS_##nb_args \
: "memory"); \
result; \
})

使用例:

1
2
3
4
5
6
7
8
9
10
11
12
int main(){
fd = SYSCALL(__NR_openat, 4, AT_FDCWD, (word_t) & "/data/local/tmp/test.txt", O_RDWR, 0); // 但是写svc的时候不可省略 mode
/**
* @brief /data/local/tmp/test.txt 文件原始内容
* no thing
*/
if (fd < 0){
printf("openat error\n");
return -1;
}
......
}

参考:
https://github.com/SsageParuders/Android_SVC_Edu

编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
set abi=arm64-v8a
SET ANDROID_SDK_HOME=C:\Users\Shocker\AppData\Local\Android\Sdk

if not exist %abi% md %abi%
cd %abi%

%ANDROID_SDK_HOME%\cmake\3.23.1\bin\cmake ^
-DANDROID_ABI=%abi% ^
-DANDROID_NDK=%ANDROID_SDK_HOME%\ndk\23.1.7779620 ^
-DCMAKE_BUILD_TYPE=Release ^
-DCMAKE_TOOLCHAIN_FILE=%ANDROID_SDK_HOME%\ndk\23.1.7779620\build\cmake\android.toolchain.cmake ^
-DANDROID_NATIVE_API_LEVEL=21 ^
-DANDROID_TOOLCHAIN=clang -DCMAKE_GENERATOR="Ninja" ^
-DCMAKE_MAKE_PROGRAM=%ANDROID_SDK_HOME%\cmake\3.23.1\bin\ninja ^
..

%ANDROID_SDK_HOME%\cmake\3.18.1\bin\ninja
cd ..