Add ci for manager and userspace (#2)
* kernel: move EXPECTED_* macro to Makefile * manager: add sign configs * tools: add check_v2 * CI: build manager * CI: build userspace
This commit is contained in:
40
.github/workflows/build-manager.yml
vendored
Normal file
40
.github/workflows/build-manager.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
name: Build Manager
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: ./manager
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: set up JDK 11
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
java-version: '11'
|
||||||
|
distribution: 'temurin'
|
||||||
|
cache: gradle
|
||||||
|
- name: Extract keystore
|
||||||
|
if: ${{ ( github.event_name != 'pull_request' && github.ref == 'refs/heads/main' ) || github.ref_type == 'tag' }}
|
||||||
|
run: |
|
||||||
|
if [ ! -z "${{ secrets.KEY_STORE }}" ]; then
|
||||||
|
echo KEYSTORE_PASSWORD='${{ secrets.KEYSTORE_PASSWORD }}' >> sign.properties
|
||||||
|
echo KEY_ALIAS='${{ secrets.KEY_ALIAS }}' >> sign.properties
|
||||||
|
echo KEY_PASSWORD='${{ secrets.KEY_PASSWORD }}' >> sign.properties
|
||||||
|
echo KEYSTORE_FILE='../key.jks' >> sign.properties
|
||||||
|
echo ${{ secrets.KEYSTORE }} | base64 --decode > key.jks
|
||||||
|
fi
|
||||||
|
- name: Grant execute permission for gradlew
|
||||||
|
run: chmod +x gradlew
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: ./gradlew build
|
||||||
|
- name: Upload build artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: manager
|
||||||
|
path: manager/app/build/outputs/apk/release/*.apk
|
||||||
|
|
||||||
24
.github/workflows/build-userspace.yml
vendored
Normal file
24
.github/workflows/build-userspace.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
name: Build Userspace
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "main" ]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: nttld/setup-ndk@v1
|
||||||
|
with:
|
||||||
|
ndk-version: r25b
|
||||||
|
local-cache: true
|
||||||
|
- name: Build with NDK
|
||||||
|
working-directory: ./userspace
|
||||||
|
run: ndk-build
|
||||||
|
- name: Upload a Build Artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: su
|
||||||
|
path: ./userspace/libs
|
||||||
|
|
||||||
@@ -6,4 +6,8 @@ obj-y += sucompat.o
|
|||||||
|
|
||||||
obj-y += selinux/
|
obj-y += selinux/
|
||||||
|
|
||||||
|
EXPECTED_SIZE := 0x033b
|
||||||
|
EXPECTED_HASH := 0xb0b91415
|
||||||
|
ccflags-y += -DEXPECTED_SIZE=$(EXPECTED_SIZE)
|
||||||
|
ccflags-y += -DEXPECTED_HASH=$(EXPECTED_HASH)
|
||||||
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
|
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
|
||||||
|
|||||||
@@ -112,9 +112,6 @@ clean:
|
|||||||
return sign;
|
return sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define EXPECTED_SIZE 0x033b
|
|
||||||
#define EXPECTED_HASH 0xb0b91415
|
|
||||||
|
|
||||||
int is_manager_apk(char* path) {
|
int is_manager_apk(char* path) {
|
||||||
return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH);
|
return check_v2_signature(path, EXPECTED_SIZE, EXPECTED_HASH);
|
||||||
}
|
}
|
||||||
2
manager/.gitignore
vendored
2
manager/.gitignore
vendored
@@ -13,3 +13,5 @@
|
|||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
.cxx
|
.cxx
|
||||||
local.properties
|
local.properties
|
||||||
|
sign.properties
|
||||||
|
key.jks
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ android {
|
|||||||
namespace 'me.weishu.kernelsu'
|
namespace 'me.weishu.kernelsu'
|
||||||
compileSdk 33
|
compileSdk 33
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
sign
|
||||||
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "me.weishu.kernelsu"
|
applicationId "me.weishu.kernelsu"
|
||||||
minSdk 26
|
minSdk 26
|
||||||
@@ -29,6 +33,7 @@ android {
|
|||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
signingConfig signingConfigs.sign
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
@@ -84,3 +89,5 @@ dependencies {
|
|||||||
debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version"
|
debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version"
|
||||||
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version"
|
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply from: rootProject.file('sign.gradle')
|
||||||
4
manager/sign.example.properties
Normal file
4
manager/sign.example.properties
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
KEYSTORE_FILE=
|
||||||
|
KEYSTORE_PASSWORD=
|
||||||
|
KEY_ALIAS=
|
||||||
|
KEY_PASSWORD=
|
||||||
16
manager/sign.gradle
Normal file
16
manager/sign.gradle
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
def ksFile = rootProject.file('sign.properties')
|
||||||
|
def props = new Properties()
|
||||||
|
if (ksFile.canRead()) {
|
||||||
|
props.load(new FileInputStream(ksFile))
|
||||||
|
if (props != null) {
|
||||||
|
android.signingConfigs.sign.storeFile file(props['KEYSTORE_FILE'])
|
||||||
|
android.signingConfigs.sign.storePassword props['KEYSTORE_PASSWORD']
|
||||||
|
android.signingConfigs.sign.keyAlias props['KEY_ALIAS']
|
||||||
|
android.signingConfigs.sign.keyPassword props['KEY_PASSWORD']
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
android.signingConfigs.sign.storeFile = android.signingConfigs.debug.storeFile
|
||||||
|
android.signingConfigs.sign.storePassword = android.signingConfigs.debug.storePassword
|
||||||
|
android.signingConfigs.sign.keyAlias = android.signingConfigs.debug.keyAlias
|
||||||
|
android.signingConfigs.sign.keyPassword = android.signingConfigs.debug.keyPassword
|
||||||
|
}
|
||||||
173
tools/check_v2.c
Normal file
173
tools/check_v2.c
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
//
|
||||||
|
// Created by Thom on 2019/3/8.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Credits: https://github.com/brevent/genuine/blob/master/src/main/jni/apk-sign-v2.c
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define MAIN
|
||||||
|
|
||||||
|
#ifdef MAIN
|
||||||
|
#include <stdio.h>
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "openat.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool isApkSigBlock42(const char *buffer) {
|
||||||
|
// APK Sig Block 42
|
||||||
|
return *buffer == 'A'
|
||||||
|
&& *++buffer == 'P'
|
||||||
|
&& *++buffer == 'K'
|
||||||
|
&& *++buffer == ' '
|
||||||
|
&& *++buffer == 'S'
|
||||||
|
&& *++buffer == 'i'
|
||||||
|
&& *++buffer == 'g'
|
||||||
|
&& *++buffer == ' '
|
||||||
|
&& *++buffer == 'B'
|
||||||
|
&& *++buffer == 'l'
|
||||||
|
&& *++buffer == 'o'
|
||||||
|
&& *++buffer == 'c'
|
||||||
|
&& *++buffer == 'k'
|
||||||
|
&& *++buffer == ' '
|
||||||
|
&& *++buffer == '4'
|
||||||
|
&& *++buffer == '2';
|
||||||
|
}
|
||||||
|
|
||||||
|
int checkSignature(const char *path) {
|
||||||
|
unsigned char buffer[0x11] = {0};
|
||||||
|
uint32_t size4;
|
||||||
|
uint64_t size8, size_of_block;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
LOGI("check signature for %s", path);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int sign = -1;
|
||||||
|
int fd = (int) openat(AT_FDCWD, path, O_RDONLY);
|
||||||
|
#ifdef DEBUG_OPENAT
|
||||||
|
LOGI("openat %s returns %d", path, fd);
|
||||||
|
#endif
|
||||||
|
if (fd < 0) {
|
||||||
|
return sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
sign = 1;
|
||||||
|
// https://en.wikipedia.org/wiki/Zip_(file_format)#End_of_central_directory_record_(EOCD)
|
||||||
|
for (int i = 0;; ++i) {
|
||||||
|
unsigned short n;
|
||||||
|
lseek(fd, -i - 2, SEEK_END);
|
||||||
|
read(fd, &n, 2);
|
||||||
|
if (n == i) {
|
||||||
|
lseek(fd, -22, SEEK_CUR);
|
||||||
|
read(fd, &size4, 4);
|
||||||
|
if ((size4 ^ 0xcafebabeu) == 0xccfbf1eeu) {
|
||||||
|
#ifdef MAIN
|
||||||
|
if (i > 0) {
|
||||||
|
printf("warning: comment length is %d\n", i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == 0xffff) {
|
||||||
|
#ifdef MAIN
|
||||||
|
printf("error: cannot find eocd\n");
|
||||||
|
#endif
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(fd, 12, SEEK_CUR);
|
||||||
|
// offset
|
||||||
|
read(fd, &size4, 0x4);
|
||||||
|
lseek(fd, (off_t) (size4 - 0x18), SEEK_SET);
|
||||||
|
|
||||||
|
read(fd, &size8, 0x8);
|
||||||
|
read(fd, buffer, 0x10);
|
||||||
|
if (!isApkSigBlock42((char *) buffer)) {
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
lseek(fd, (off_t) (size4 - (size8 + 0x8)), SEEK_SET);
|
||||||
|
read(fd, &size_of_block, 0x8);
|
||||||
|
if (size_of_block != size8) {
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t offset;
|
||||||
|
read(fd, &size8, 0x8); // sequence length
|
||||||
|
if (size8 == size_of_block) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read(fd, &id, 0x4); // id
|
||||||
|
offset = 4;
|
||||||
|
#ifdef MAIN
|
||||||
|
// printf("id: 0x%08x\n", id);
|
||||||
|
#endif
|
||||||
|
if ((id ^ 0xdeadbeefu) == 0xafa439f5u || (id ^ 0xdeadbeefu) == 0x2efed62f) {
|
||||||
|
read(fd, &size4, 0x4); // signer-sequence length
|
||||||
|
read(fd, &size4, 0x4); // signer length
|
||||||
|
read(fd, &size4, 0x4); // signed data length
|
||||||
|
offset += 0x4 * 3;
|
||||||
|
|
||||||
|
read(fd, &size4, 0x4); // digests-sequence length
|
||||||
|
lseek(fd, (off_t) (size4), SEEK_CUR);// skip digests
|
||||||
|
offset += 0x4 + size4;
|
||||||
|
|
||||||
|
read(fd, &size4, 0x4); // certificates length
|
||||||
|
read(fd, &size4, 0x4); // certificate length
|
||||||
|
offset += 0x4 * 2;
|
||||||
|
#ifdef MAIN
|
||||||
|
int hash = 1;
|
||||||
|
signed char c;
|
||||||
|
for (unsigned i = 0; i < size4; ++i) {
|
||||||
|
read(fd, &c, 0x1);
|
||||||
|
hash = 31 * hash + c;
|
||||||
|
}
|
||||||
|
offset += size4;
|
||||||
|
// printf(" size: 0x%04x, hash: 0x%08x\n", size4, ((unsigned) hash) ^ 0x14131211u);
|
||||||
|
printf("0x%04x 0x%08x\n", size4, ((unsigned) hash) ^ 0x14131211u);
|
||||||
|
#else
|
||||||
|
#if defined(GENUINE_SIZE) && defined(GENUINE_HASH)
|
||||||
|
if (size4 == GENUINE_SIZE) {
|
||||||
|
int hash = 1;
|
||||||
|
signed char c;
|
||||||
|
for (unsigned i = 0; i < size4; ++i) {
|
||||||
|
read(fd, &c, 0x1);
|
||||||
|
hash = 31 * hash + c;
|
||||||
|
}
|
||||||
|
offset += size4;
|
||||||
|
if ((((unsigned) hash) ^ 0x14131211u) == GENUINE_HASH) {
|
||||||
|
sign = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
sign = 0;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
lseek(fd, (off_t) (size8 - offset), SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MAIN
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc > 1) {
|
||||||
|
checkSignature(argv[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user