First commit
This commit is contained in:
commit
8b2d63fcaa
47 changed files with 4761 additions and 0 deletions
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal 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
3
.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
6
.idea/compiler.xml
generated
Normal file
6
.idea/compiler.xml
generated
Normal 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
20
.idea/gradle.xml
generated
Normal 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
10
.idea/misc.xml
generated
Normal 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
6
.idea/vcs.xml
generated
Normal 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
3
README.MD
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# ApkSignatureKillerEx
|
||||
|
||||
本项目演示了 MT 去除签名校验功能的原理,以及它的一种对抗方式。
|
||||
1
app/.gitignore
vendored
Normal file
1
app/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
30
app/CMakeLists.txt
Normal file
30
app/CMakeLists.txt
Normal 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
53
app/build.gradle
Normal 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')
|
||||
}
|
||||
22
app/src/main/AndroidManifest.xml
Normal file
22
app/src/main/AndroidManifest.xml
Normal 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
66
app/src/main/c/openat.c
Normal 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
27
app/src/main/c/openat.h
Normal 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
|
||||
145
app/src/main/java/bin/mt/test/MainActivity.java
Normal file
145
app/src/main/java/bin/mt/test/MainActivity.java
Normal 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);
|
||||
|
||||
}
|
||||
16
app/src/main/res/layout/activity_main.xml
Normal file
16
app/src/main/res/layout/activity_main.xml
Normal 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>
|
||||
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
5
build.gradle
Normal file
5
build.gradle
Normal 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
BIN
fake.jks
Normal file
Binary file not shown.
21
gradle.properties
Normal file
21
gradle.properties
Normal 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
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
Loading…
Reference in a new issue