First commit

This commit is contained in:
L-JINBIN 2022-12-25 16:49:43 +08:00
commit 8b2d63fcaa
47 changed files with 4761 additions and 0 deletions

15
.gitignore vendored Normal file
View file

@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

3
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

6
.idea/compiler.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
</component>
</project>

20
.idea/gradle.xml generated Normal file
View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/killer" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

10
.idea/misc.xml generated Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

6
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

3
README.MD Normal file
View file

@ -0,0 +1,3 @@
# ApkSignatureKillerEx
本项目演示了 MT 去除签名校验功能的原理,以及它的一种对抗方式。

1
app/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

30
app/CMakeLists.txt Normal file
View file

@ -0,0 +1,30 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
test
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main/c/openat.c
)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
target_link_libraries( # Specifies the target library.
test
# Links the target library to the log library
# included in the NDK.
${log-lib})

53
app/build.gradle Normal file
View file

@ -0,0 +1,53 @@
plugins {
id 'com.android.application'
}
android {
namespace 'bin.mt.test'
compileSdk 32
ndkVersion '24.0.8215888'
defaultConfig {
applicationId "bin.mt.signature"
minSdk 21
//noinspection OldTargetApi
targetSdk 32
versionCode 1
versionName "1.0"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters = ["armeabi-v7a", "x86", "arm64-v8a", "x86_64"]
}
}
ndk {
abiFilters = ["armeabi-v7a", "x86", "arm64-v8a", "x86_64"]
}
}
signingConfigs {
debug {
storeFile file("../fake.jks")
storePassword "123456"
keyAlias "key0"
keyPassword "123456"
v1SigningEnabled true
v2SigningEnabled true
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation project(path: ':killer')
}

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".MainActivity$App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="ApkSignatureKillerEx"
android:supportsRtl="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

66
app/src/main/c/openat.c Normal file
View file

@ -0,0 +1,66 @@
//
// Created by Thom on 2019/3/30.
//
#include <unistd.h>
#include <sys/syscall.h>
#include "openat.h"
#include <jni.h>
#include <android/log.h>
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
intptr_t openAt(intptr_t fd, const char *path, intptr_t flag) {
#if defined(__arm__)
intptr_t r;
asm volatile(
#ifndef OPTIMIZE_ASM
"mov r0, %1\n\t"
"mov r1, %2\n\t"
"mov r2, %3\n\t"
#endif
"mov ip, r7\n\t"
".cfi_register r7, ip\n\t"
"mov r7, #" STR(__NR_openat) "\n\t"
"svc #0\n\t"
"mov r7, ip\n\t"
".cfi_restore r7\n\t"
#ifndef OPTIMIZE_ASM
"mov %0, r0\n\t"
#endif
: "=r" (r)
: "r" (fd), "r" (path), "r" (flag));
return r;
#elif defined(__aarch64__)
intptr_t r;
asm volatile(
#ifndef OPTIMIZE_ASM
"mov x0, %1\n\t"
"mov x1, %2\n\t"
"mov x2, %3\n\t"
#endif
"mov x8, #" STR(__NR_openat) "\n\t"
"svc #0\n\t"
#ifndef OPTIMIZE_ASM
"mov %0, x0\n\t"
#endif
: "=r" (r)
: "r" (fd), "r" (path), "r" (flag));
return r;
#else
return (intptr_t) syscall(__NR_openat, fd, path, flag);
#endif
}
JNIEXPORT jint JNICALL
Java_bin_mt_test_MainActivity_openAt(JNIEnv *env, __attribute__((unused)) jclass clazz, jstring path) {
const char* p = (*env)->GetStringUTFChars(env, path, 0);
__android_log_print(ANDROID_LOG_INFO, "openAt", "path=%s", p);
intptr_t fd = openAt(AT_FDCWD, p, O_RDONLY);
return fd;
}

27
app/src/main/c/openat.h Normal file
View file

@ -0,0 +1,27 @@
//
// Created by Thom on 2019/3/30.
//
#ifndef BREVENT_OPENAT_H
#define BREVENT_OPENAT_H
#include <stdint.h>
#include <fcntl.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __ANDROID__
intptr_t openAt(intptr_t fd, const char *path, intptr_t flag);
#else
#define openAt openat
#endif
#ifdef __cplusplus
}
#endif
#endif //BREVENT_OPENAT_H

View file

@ -0,0 +1,145 @@
package bin.mt.test;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.widget.TextView;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
public class MainActivity extends Activity {
public static class App extends Application {
@Override
protected void attachBaseContext(Context base) {
new bin.mt.signature.KillerApplication(); // 注释掉这句即可关闭过签
super.attachBaseContext(base);
}
}
static {
System.loadLibrary("test");
}
@SuppressLint("SetTextI18n")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView msg = findViewById(R.id.msg);
// 以下演示了三种获取签名MD5的方式
String signatureExpected = "3bf8931788824c6a1f2c6f6ff80f6b21";
String signatureFromAPI = md5(signatureFromAPI());
String signatureFromAPK = md5(signatureFromAPK());
String signatureFromSVC = md5(signatureFromSVC());
// 开启过签后,API与APK方式会获取到虚假的签名MD5
// 而SVC方式总是能获取到真实的签名MD5
SpannableStringBuilder sb = new SpannableStringBuilder();
append(sb, "Expected: ", signatureExpected, Color.BLACK);
append(sb, "From API: ", signatureFromAPI, signatureExpected.equals(signatureFromAPI) ? Color.BLUE : Color.RED);
append(sb, "From APK: ", signatureFromAPK, signatureExpected.equals(signatureFromAPK) ? Color.BLUE : Color.RED);
append(sb, "From SVC: ", signatureFromSVC, signatureExpected.equals(signatureFromSVC) ? Color.BLUE : Color.RED);
// 当然SVC并非绝对安全,只是相对而言更加可靠,实际运用还需结合更多的手段
msg.setText(sb);
}
private static void append(SpannableStringBuilder sb, String header, String value, int color) {
int start = sb.length();
sb.append(header).append(value).append("\n");
int end = sb.length();
sb.setSpan(new ForegroundColorSpan(color), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
private byte[] signatureFromAPI() {
try {
@SuppressLint("PackageManagerGetSignatures")
PackageInfo info = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
return info.signatures[0].toByteArray();
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
}
private byte[] signatureFromAPK() {
try (ZipFile zipFile = new ZipFile(getPackageResourcePath())) {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (entry.getName().matches("(META-INF/.*)\\.(RSA|DSA|EC)")) {
InputStream is = zipFile.getInputStream(entry);
CertificateFactory certFactory = CertificateFactory.getInstance("X509");
X509Certificate x509Cert = (X509Certificate) certFactory.generateCertificate(is);
return x509Cert.getEncoded();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private byte[] signatureFromSVC() {
try (ParcelFileDescriptor fd = ParcelFileDescriptor.adoptFd(openAt(getPackageResourcePath()));
ZipInputStream zis = new ZipInputStream(new FileInputStream(fd.getFileDescriptor()))) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
if (entry.getName().matches("(META-INF/.*)\\.(RSA|DSA|EC)")) {
CertificateFactory certFactory = CertificateFactory.getInstance("X509");
X509Certificate x509Cert = (X509Certificate) certFactory.generateCertificate(zis);
return x509Cert.getEncoded();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private String md5(byte[] bytes) {
if (bytes == null) {
return "null";
}
try {
byte[] digest = MessageDigest.getInstance("MD5").digest(bytes);
String hexDigits = "0123456789abcdef";
char[] str = new char[digest.length * 2];
int k = 0;
for (byte b : digest) {
str[k++] = hexDigits.charAt(b >>> 4 & 0xf);
str[k++] = hexDigits.charAt(b & 0xf);
}
return new String(str);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static native int openAt(String path);
}

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/msg"
android:typeface="monospace"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

5
build.gradle Normal file
View file

@ -0,0 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.3.0' apply false
id 'com.android.library' version '7.3.0' apply false
}

BIN
fake.jks Normal file

Binary file not shown.

21
gradle.properties Normal file
View file

@ -0,0 +1,21 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more