From 6ed271cd5ccb684601577f4208491b70543fb883 Mon Sep 17 00:00:00 2001 From: 4ra1n <2023503307@qq.com> Date: Sat, 9 Sep 2023 15:21:50 +0800 Subject: [PATCH] commit --- .gitignore | 44 +++++ README.md | 65 +++++++ img/001.png | Bin 0 -> 5666 bytes img/002.png | Bin 0 -> 9476 bytes img/003.png | Bin 0 -> 59951 bytes native/CMakeLists.txt | 98 +++++++++++ native/core_de.h | 9 + native/core_en.h | 9 + native/decrypt.asm | 62 +++++++ native/decrypt_test.c | 19 ++ native/encrypt.asm | 69 ++++++++ native/encryptor.c | 72 ++++++++ native/encryptor.h | 21 +++ native/main.py | 21 +++ native/start.c | 164 ++++++++++++++++++ native/xxtea.c | 28 +++ native/xxtea_common.c | 16 ++ native/xxtea_common.h | 8 + native/xxtea_de.h | 11 ++ native/xxtea_en.h | 11 ++ native/xxtea_test.c | 39 +++++ pom.xml | 145 ++++++++++++++++ script/README.md | 19 ++ .../org/y4sec/encryptor/cli/Application.java | 64 +++++++ .../java/org/y4sec/encryptor/cli/Command.java | 5 + .../y4sec/encryptor/cli/ExportCommand.java | 24 +++ .../org/y4sec/encryptor/cli/PatchCommand.java | 33 ++++ .../y4sec/encryptor/core/CodeEncryptor.java | 14 ++ .../org/y4sec/encryptor/core/Constants.java | 16 ++ .../org/y4sec/encryptor/core/PatchHelper.java | 94 ++++++++++ .../java/org/y4sec/encryptor/gui/GUIMain.java | 10 ++ .../org/y4sec/encryptor/gui/MainForm.form | 127 ++++++++++++++ .../org/y4sec/encryptor/gui/MainForm.java | 155 +++++++++++++++++ .../org/y4sec/encryptor/util/ByteUtil.java | 25 +++ .../org/y4sec/encryptor/util/JNIUtil.java | 138 +++++++++++++++ src/main/resources/decrypter.dll | Bin 0 -> 13312 bytes src/main/resources/encryptor.dll | Bin 0 -> 11776 bytes src/main/resources/log4j2.xml | 13 ++ 38 files changed, 1648 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 img/001.png create mode 100644 img/002.png create mode 100644 img/003.png create mode 100644 native/CMakeLists.txt create mode 100644 native/core_de.h create mode 100644 native/core_en.h create mode 100644 native/decrypt.asm create mode 100644 native/decrypt_test.c create mode 100644 native/encrypt.asm create mode 100644 native/encryptor.c create mode 100644 native/encryptor.h create mode 100644 native/main.py create mode 100644 native/start.c create mode 100644 native/xxtea.c create mode 100644 native/xxtea_common.c create mode 100644 native/xxtea_common.h create mode 100644 native/xxtea_de.h create mode 100644 native/xxtea_en.h create mode 100644 native/xxtea_test.c create mode 100644 pom.xml create mode 100644 script/README.md create mode 100644 src/main/java/org/y4sec/encryptor/cli/Application.java create mode 100644 src/main/java/org/y4sec/encryptor/cli/Command.java create mode 100644 src/main/java/org/y4sec/encryptor/cli/ExportCommand.java create mode 100644 src/main/java/org/y4sec/encryptor/cli/PatchCommand.java create mode 100644 src/main/java/org/y4sec/encryptor/core/CodeEncryptor.java create mode 100644 src/main/java/org/y4sec/encryptor/core/Constants.java create mode 100644 src/main/java/org/y4sec/encryptor/core/PatchHelper.java create mode 100644 src/main/java/org/y4sec/encryptor/gui/GUIMain.java create mode 100644 src/main/java/org/y4sec/encryptor/gui/MainForm.form create mode 100644 src/main/java/org/y4sec/encryptor/gui/MainForm.java create mode 100644 src/main/java/org/y4sec/encryptor/util/ByteUtil.java create mode 100644 src/main/java/org/y4sec/encryptor/util/JNIUtil.java create mode 100644 src/main/resources/decrypter.dll create mode 100644 src/main/resources/encryptor.dll create mode 100644 src/main/resources/log4j2.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f9c7af --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store + +### Others ### +.idea/ +cmake-build-debug/ +cmake-build-release/ +*.exe \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a84cd6b --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# code-encryptor-plus + +## 介绍 + +使用`JNI`加密字节码,通过`JVMTI`解密字节码以保护代码 + +提供两份`DLL`文件,一份加密一份解密,实际运行只需使用解密`DLL`文件 + +加密和解密的过程可以指定具体的包名,只加密核心关键部分 + +详细文章参考:[JVMTI 加密字节码详解](http://127.0.0.1:8080) + +加密后的`Class`文件变成无法解析的畸形文件 + +![jd-gui](img/002.png) + +除了开头保持了`Magic`部分,后续是无法解析的字节 + +![hex](img/003.png) + +## 快速开始 + +加密解密部分使用`C`做一层加密,使用`汇编`二层加密,已提供编译好的`Release`版本`DLL`文件嵌入`Jar`包中 + +仅支持`Windows 64位`/`JDK-8`环境,其他版本的`JDK`只需要更换`JNI.h`头文件重新编译,其他操作系统可能需要重写 + +加密你的`Jar`包:(指定`Jar`包和`package`加密包名) + +```shell + java -jar code-encryptor-plus.jar patch --jar your-jar.jar --package com.your.pack +``` + +导出解密`DLL`文件:(默认导出到`code-encryptor-plus-temp`目录) + +```shell +java -jar code-encryptor-plus.jar export +``` + +使用解密`DLL`启动`Jar`包:(使用`-agentlib`参数) + +```shell +java -agentlib:D:\abs-path\decrypter=PACKAGE_NAME=com.your.pack --jar your-jar.jar +``` + +另外支持了简易的`GUI`版本,选择需要加密的`Jar`文件即可一键加密 + +![screenshot](img/001.png) + +## 其他 + +不适用于`SpringBoot`场景,存在两个问题: +- `SpringBoot`不允许压缩`lib`依赖(这个有解决办法) +- `SpringBoot`启动扫描会分析`class`由于加密报错 + +网上提供了两种办法,可以参考 + +参考:https://zhuanlan.zhihu.com/p/545268749 + +类似地,启动扫描`class`的代码是无法使用这种加密的 + +## 致谢 + +感谢以下项目或文章提供的思路: +- https://juejin.cn/post/6844903487784894477 +- https://github.com/sea-boat/ByteCodeEncrypt \ No newline at end of file diff --git a/img/001.png b/img/001.png new file mode 100644 index 0000000000000000000000000000000000000000..2f88e903f0631ae0485002f8996ad1a16ded0d94 GIT binary patch literal 5666 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 literal 0 HcmV?d00001 diff --git a/img/002.png b/img/002.png new file mode 100644 index 0000000000000000000000000000000000000000..aec302e6445b7fa196decc918e60926bf5a3a735 GIT binary patch literal 9476 zcmaiadpwix|NkwON|6p!PD#=`=M*tU5lV$}3`6D6%Ly+=kxWtuH7|0r@v*>o=pG%Y&m71dmaGR zq=Nr{-LMAyo2eQ$4FLOFPU#*u4S-Re(qg470@FwM`?2_fTM6V1i1PS5H>4~!!y-Kn zif_%|EAUUFz?F-Zr*{dL>iA{vOt!KX*3QX3+M#$aCB9t1GIZ_74Ww6VjpN#5w65%L zOy6G-#UtDhr1ACpRDTj%iPU?+H}Bljpf)uR3&KJNGnJ*Geu#)1Pq{!y%t#9vCnBzh z1A8H`(T1+BuG~dmQWPmK@aI6p;+C?y1&?Y|k@&?30I&?s!kJZWgD2jve|Cc;{Tj~- z(~6S-Lc8}-3d_Pt%InblBg|R`+8;IBQiP*4Zd}alKEwk6XLeupcqrGI`cDq7zlt{h zHE8p8CUztHN8jSYUGarcw6^%XWX zgk(8Cu7IDPMJ*7u@IG&I$crwO@3^FdW%M^^qR(PNt~h31EG@WpB)P^wvwC)GS(S=c zSdHyt3HqZB(uJucuDv`<7R==@ypD!czTKi|l+IXVM`7Y<_eBZp82qg8S1(B~I|_A4 zZ_@{ra*eLOt`yQS#O1;-6_o=w9ka4TuE)iMvm?m_l-wPpTajqK^ZHQPIEH*+i*@fl z9Vu%~f_oG@OdRh+({BrzoGO0j_De|SBpIjK6Gb9d7cu%4#_{a0BWbFFsuVnXGGcL{ zjotdokewJWt}+%zgX%#KitXw`876jC?rs8zUN$uVp6r+>+#B}JKaxSI`_`azIjI? z<;;5&_Dt@mimO<-cGzF3Q6j<1!#MsY3(jP5YeP2#LW=b%wMTE0{QYRvezWxrpOJes zg656fAc_aIDeLqGh{bm0@2^nYZQDqwkz)2cyvK)t@dI` zi}iTMP!GB}y8kt0t`^wK6YR~>izOjlH={jhR5#jVKVn5%h(BHWekB5liu-x=Xs(^j z{U_Nc2Omd#oi8lV1r5_1P$2F?V|{HYi{IZ$KkON8HCIc2HZN^9zkL^4`TLxmj(38_ z1E1(&hG*yL>%!#Hj)Px>fN$X*?gP_G1b14hHyn?{`6F1=ek2! z%iQb9gfnS%$=~oAz+;(UZ{GNb_`(lx%=yK}ZjWTAPWML`>IAtOC;iASXz;05*7Hwt zbrRcIj*hf5sT;RLoD59|I@0;!3cDCKEF@|+k&X1$qp)iSzM$x*(JQG%6(BUcNtJoy8r>9os_U#W3_m+gPWGVQ zZpk*n8OBuXsD(@l_Q##N>UI8ykHa);Q!$z)o|(=Vh^l4#e)S;s`VHP%?6~%j8vtHJ zRbbwkJELht>2C_Ds7bo2U!Sf+)@}<_PQo6EbBXPp z4!bufOS`3-&sCT^Uiz+KK)q%s=3QXutxNB8XyifrOXvFe^9S2)V>WODt$ZK?6hh&c z6k8Eg~8`St<}-Vj)-J*y|aLLU5wj&y%Gtl&T@fffZu?f=qqo@OK|bV& zb&dV>Y^FvdMGbnGO`nEvS_Tz>UzDl;(L8v%H#j7Leu=KcRYF;EN zg&wcsdgE&kB37h){F6v5G5?7|l(}Mj9zN!ZniN?w@miNo>Yr2q#-n8GFR&($qfsLrCn$Q~!dvjj4|!zde=tS?e;$!Nk=BR!?wY2$ zv07kuF>tOEwOAMSmtHxV7mN`%%n-#vlvpv`NNYqd{IG9N6w%FFpxg}W+^ad!Pu)lt z!yU9}8PR?>BK5L-EuhX}I-y@e=&=irP<<&=)xZ3<=SvIkmmgw-;TxMIQyt%0V8118 z1x9ay#U%)D+tCRtf#$$i7VK|*GMJ8}LN9F{7gwQDnSpIUzx`6Mj1ez>SqQBr;b-*m zxnK00K_6`y7~j}XAd2SJ_E=do-&1z@#t3PVDb9WY3OB+25+0l
Y-F@$F1)n(Xv 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 K=@y-^zxjWZPf<|- literal 0 HcmV?d00001 diff --git a/img/003.png b/img/003.png new file mode 100644 index 0000000000000000000000000000000000000000..ae26835e84bf93382a4e1424be4980a2ca487e15 GIT binary patch literal 59951 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:Debug>" +) + +set_property(TARGET native_decrypt_asm PROPERTY + MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" +) + +add_dependencies(encryptor native_encrypt_asm) + +add_dependencies(decrypter native_decrypt_asm) + +target_link_libraries(encryptor + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/native_encrypt_asm.obj +) + +target_link_libraries(decrypter + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/native_decrypt_asm.obj +) + +add_executable( + xxtea_test + xxtea_common.h + xxtea_common.c + xxtea_en.h + xxtea_de.h + xxtea.c + xxtea_test.c +) + +add_executable( + decrypt_test + core_de.h + decrypt_test.c +) + +target_link_libraries(decrypt_test + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/native_decrypt_asm.obj +) \ No newline at end of file diff --git a/native/core_de.h b/native/core_de.h new file mode 100644 index 0000000..1a1752d --- /dev/null +++ b/native/core_de.h @@ -0,0 +1,9 @@ +#ifndef NATIVE_CORE_DE_H +#define NATIVE_CORE_DE_H + +#endif //NATIVE_CORE_DE_H + +#define LOG(msg) printf("[JVMTI-LOG] %s\n", msg) + +// SEE decrypt.asm +extern void decrypt(unsigned char *, long); \ No newline at end of file diff --git a/native/core_en.h b/native/core_en.h new file mode 100644 index 0000000..9af7baa --- /dev/null +++ b/native/core_en.h @@ -0,0 +1,9 @@ +#ifndef NATIVE_CORE_EN_H +#define NATIVE_CORE_EN_H + +#endif //NATIVE_CORE_EN_H + +#define LOG(msg) printf("[ENCRYPT] %s\n", msg) + +// SEE encrypt.asm +extern void encrypt(unsigned char *, long); diff --git a/native/decrypt.asm b/native/decrypt.asm new file mode 100644 index 0000000..efb6dd7 --- /dev/null +++ b/native/decrypt.asm @@ -0,0 +1,62 @@ +.code +; FUNCTION decrypt +decrypt PROC + ; init + push rbp + mov rbp, rsp + ; save + push rbx + push rsi + push rdi + ; char* str + mov rdi, rcx + ; long length + mov rcx, rdx + ; rbx = 0 + xor rbx, rbx + ; rbx = rbx + 4 + add rbx, 004h + ; signature + mov rsi, rcx + sub rsi, 001h + mov al, byte ptr [rdi+rsi] + mov ah, byte ptr [rdi+004h] + mov byte ptr [rdi+004h], al + mov byte ptr [rdi+rsi], ah + ; reset + xor ah, ah + xor al, al + xor rsi, rsi +link_start: + ; if ebx >= ecx goto end + cmp rbx, rcx + jge magic + ; al = str[rdi+rbx] + mov al, byte ptr [rdi+rbx] + ; al = al ^ 22 + xor al, 022h + ; al = al -1 + sub al, 001h + ; al = ~al + not al + ; al = al ^ 11h + xor al, 011h + ; al = al + 2 + add al, 002h + ; str[rdi+rbx] = al + mov byte ptr [rdi+rbx], al + ; ebx ++ + inc ebx + ; loop + jmp link_start +magic: + ; recover + pop rdi + pop rsi + pop rbx + ; recover rbp + pop rbp + ret +decrypt ENDP + +end diff --git a/native/decrypt_test.c b/native/decrypt_test.c new file mode 100644 index 0000000..85df31a --- /dev/null +++ b/native/decrypt_test.c @@ -0,0 +1,19 @@ +#include "core_de.h" +#include "stdio.h" + +void printHex(const unsigned char *arr, int length) { + for (int i = 0; i < length; i++) { + printf("%02X", arr[i]); + } + printf("\n"); +} + +int main() { + unsigned char code[12] = { + 0xca, 0xfe, 0xba, 0xbe, + 0x00, 0x00, 0x00, 0x05, + 0x01, 0x02, 0x03, 0x04, + }; + decrypt(code,12); + printHex(code,12); +} \ No newline at end of file diff --git a/native/encrypt.asm b/native/encrypt.asm new file mode 100644 index 0000000..4c98feb --- /dev/null +++ b/native/encrypt.asm @@ -0,0 +1,69 @@ +.code +; FUNCTION encrypt +encrypt PROC + ; init + push rbp + mov rbp, rsp + ; save + push rbx + push rsi + push rdi + ; char* str + mov rdi, rcx + ; long length + mov rcx, rdx + ; rbx = 0 + xor rbx, rbx +link_start: + ; if rbx >= rcx goto end + cmp rbx, rcx + jge magic + ; al = str[rdi+rbx] + mov al, byte ptr [rdi+rbx] + ; al = al - 2 + sub al, 002h + ; al = al ^ 11h + xor al, 011h + ; al = ~al + not al + ; al = al + 1 + add al, 001h + ; al = al ^ 22 + xor al, 022h + ; str[rdi+rbx] = al + mov byte ptr [rdi+rbx], al + ; ebx ++ + inc rbx + ; loop + jmp link_start +magic: + ; magic + mov al, 0CAh + mov byte ptr [rdi+000h], al + mov al, 0FEh + mov byte ptr [rdi+001h], al + mov al, 0BAh + mov byte ptr [rdi+002h], al + mov al, 0BEh + mov byte ptr [rdi+003h], al + ; signature + mov rsi, rcx + sub rsi, 001h + mov al, byte ptr [rdi+rsi] + mov ah, byte ptr [rdi+004h] + mov byte ptr [rdi+004h], al + mov byte ptr [rdi+rsi], ah + ; reset + xor ah, ah + xor al, al + xor rsi, rsi + ; recover + pop rdi + pop rsi + pop rbx + ; recover rbp + pop rbp + ret +encrypt ENDP + +end diff --git a/native/encryptor.c b/native/encryptor.c new file mode 100644 index 0000000..b221509 --- /dev/null +++ b/native/encryptor.c @@ -0,0 +1,72 @@ +#include "encryptor.h" +#include "xxtea_en.h" + +#include "string.h" +#include "stdlib.h" +#include "core_en.h" + +void internal(unsigned char *chars, int start) { + unsigned char first[4]; + for (int i = start; i < start + 4; i++) { + first[i - start] = chars[i]; + } + unsigned char second[4]; + for (int i = start + 4; i < start + 8; i++) { + second[i - start - 4] = chars[i]; + } + uint32_t v[2] = {convert(first), convert(second)}; + // key: Y4Sec-Team-4ra1n + // 59345365 632D5465 616D2D34 7261316E + uint32_t const k[4] = { + (unsigned int) 0x65533459, (unsigned int) 0x65542d63, + (unsigned int) 0X342d6d61, (unsigned int) 0x6e316172, + }; + tea_encrypt(v, k); + unsigned char first_arr[4]; + unsigned char second_arr[4]; + revert(v[0], first_arr); + revert(v[1], second_arr); + for (int i = start; i < start + 4; i++) { + chars[i] = first_arr[i - start]; + } + for (int i = start + 4; i < start + 8; i++) { + chars[i] = second_arr[i - start - 4]; + } +} + +// ClassFile { +// u4 magic; (ignore) +// u2 minor_version; (ignore) +// u2 major_version; (ignore) +// u2 constant_pool_count; (ignore) +// cp_info constant_pool[constant_pool_count-1]; +// ... +// } +// start index: 4+2+2+2=10 +// 1. asm encrypt +// 2. tea encrypt: {[10:14],[14:18]} {[18:22],[22:26]} {[26:30],[30:34]} +JNIEXPORT jbyteArray JNICALL Java_org_y4sec_encryptor_core_CodeEncryptor_encrypt + (JNIEnv *env, jclass cls, jbyteArray text, jint length) { + jbyte *data = (*env)->GetByteArrayElements(env, text, NULL); + unsigned char *chars = (unsigned char *) malloc(length); + memcpy(chars, data, length); + // 1. asm encrypt + encrypt(chars, length); + LOG("ASM ENCRYPT FINISH"); + // 2. tea encrypt + if (length < 34) { + LOG("ERROR: BYTE CODE TOO SHORT"); + return text; + } + // {[10:14],[14:18]} + internal(chars, 10); + LOG("TEA ENCRYPT #1"); + // {[18:22],[22:26]} + internal(chars, 18); + LOG("TEA ENCRYPT #2"); + // {[26:30],[30:34]} + internal(chars, 26); + LOG("TEA ENCRYPT #3"); + (*env)->SetByteArrayRegion(env, text, 0, length, (jbyte *) chars); + return text; +} \ No newline at end of file diff --git a/native/encryptor.h b/native/encryptor.h new file mode 100644 index 0000000..31f05df --- /dev/null +++ b/native/encryptor.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_y4sec_encryptor_core_CodeEncryptor */ + +#ifndef _Included_org_y4sec_encryptor_core_CodeEncryptor +#define _Included_org_y4sec_encryptor_core_CodeEncryptor +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_y4sec_encryptor_core_CodeEncryptor + * Method: encrypt + * Signature: ([BI)[B + */ +JNIEXPORT jbyteArray JNICALL Java_org_y4sec_encryptor_core_CodeEncryptor_encrypt + (JNIEnv *, jclass, jbyteArray, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/native/main.py b/native/main.py new file mode 100644 index 0000000..7f2b288 --- /dev/null +++ b/native/main.py @@ -0,0 +1,21 @@ +import os +import shutil + + +def copy_dll_files(source_dir, target_dir): + os.makedirs(target_dir, exist_ok=True) + for root, dirs, files in os.walk(source_dir): + for file in files: + if file.endswith(".dll"): + source_path = os.path.join(root, file) + target_path = os.path.join(target_dir, file) + shutil.copy(source_path, target_path) + print(f"copy: {source_path} -> {target_path}") + + +# DO NOT USE DEBUG +source_directory = "cmake-build-release" + +target_directory = "target" + +copy_dll_files(source_directory, target_directory) diff --git a/native/start.c b/native/start.c new file mode 100644 index 0000000..d05b7c7 --- /dev/null +++ b/native/start.c @@ -0,0 +1,164 @@ +#include +#include "xxtea_de.h" +#include "core_de.h" +#include "stdlib.h" +#include "string.h" + +// PACKAGE +char *PACKAGE_NAME; + +void internal(unsigned char *_data, int start) { + unsigned char first[4]; + for (int i = start; i < start + 4; i++) { + first[i - start] = _data[i]; + } + unsigned char second[4]; + for (int i = start + 4; i < start + 8; i++) { + second[i - start - 4] = _data[i]; + } + uint32_t v[2] = {convert(first), convert(second)}; + // key: Y4Sec-Team-4ra1n + // 59345365 632D5465 616D2D34 7261316E + uint32_t const k[4] = { + (unsigned int) 0x65533459, (unsigned int) 0x65542d63, + (unsigned int) 0X342d6d61, (unsigned int) 0x6e316172, + }; + tea_decrypt(v, k); + unsigned char first_arr[4]; + unsigned char second_arr[4]; + revert(v[0], first_arr); + revert(v[1], second_arr); + for (int i = start; i < start + 4; i++) { + _data[i] = first_arr[i - start]; + } + for (int i = start + 4; i < start + 8; i++) { + _data[i] = second_arr[i - start - 4]; + } +} + +// 1. tea encrypt +// 2. asm encrypt +void JNICALL ClassDecryptHook( + jvmtiEnv *jvmti_env, + JNIEnv *jni_env, + jclass class_being_redefined, + jobject loader, + const char *name, + jobject protection_domain, + jint class_data_len, + const unsigned char *class_data, + jint *new_class_data_len, + unsigned char **new_class_data) { + *new_class_data_len = class_data_len; + (*jvmti_env)->Allocate(jvmti_env, class_data_len, new_class_data); + unsigned char *_data = *new_class_data; + if (name && strncmp(name, PACKAGE_NAME, strlen(PACKAGE_NAME)) == 0) { + for (int i = 0; i < class_data_len; i++) { + _data[i] = class_data[i]; + } + if (class_data_len < 34) { + return; + } + // 1. {[10:14],[14:18]} + internal(_data,10); + // 2. {[18:22],[22:26]} + internal(_data,18); + // 3. {[26:30],[30:34]} + internal(_data,26); + // 4. asm encrypt + decrypt((unsigned char *) _data, class_data_len); + } else { + for (int i = 0; i < class_data_len; i++) { + _data[i] = class_data[i]; + } + } +} + +JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) { + LOG("UNLOAD AGENT"); +} + +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { + printf("PARAMS: %s\n", options); + + const char *key = "PACKAGE_NAME"; + char *value = NULL; + + // REPLACE . -> / + char modified_str[256]; + size_t modified_str_size = sizeof(modified_str); + strncpy_s(modified_str, modified_str_size, + options, modified_str_size - 1); + modified_str[modified_str_size - 1] = '\0'; + + for (size_t i = 0; modified_str[i] != '\0'; ++i) { + if (modified_str[i] == '.') { + modified_str[i] = '/'; + } + } + + // SPLIT A=B -> B + char *context; + char *token = strtok_s(modified_str, "=", &context); + while (token != NULL) { + if (strcmp(token, key) == 0) { + value = strtok_s(NULL, "=", &context); + break; + } + token = strtok_s(NULL, "=", &context); + } + + if (value == NULL) { + LOG("NEED PACKAGE_NAME PARAMS\n"); + return 0; + } + + // SET PACKAGE_NAME + PACKAGE_NAME = (char *) malloc(strlen(value) + 1); + strcpy_s(PACKAGE_NAME, strlen(value) + 1, value); + + printf("PACKAGE: %s\n", PACKAGE_NAME); + printf("PACKAGE-LENGTH: %llu\n", strlen(PACKAGE_NAME)); + + jvmtiEnv *jvmti; + LOG("INIT JVMTI ENVIRONMENT"); + jint ret = (*vm)->GetEnv(vm, (void **) &jvmti, JVMTI_VERSION); + if (JNI_OK != ret) { + printf("ERROR: Unable to access JVMTI!\n"); + printf("PLEASE USE JVM VERSION 8"); + return ret; + } + LOG("INIT JVMTI CAPABILITIES"); + jvmtiCapabilities capabilities; + (void) memset(&capabilities, 0, sizeof(capabilities)); + + capabilities.can_generate_all_class_hook_events = 1; + + LOG("ADD JVMTI CAPABILITIES"); + jvmtiError error = (*jvmti)->AddCapabilities(jvmti, &capabilities); + if (JVMTI_ERROR_NONE != error) { + printf("ERROR: Unable to AddCapabilities JVMTI!\n"); + return error; + } + + LOG("INIT JVMTI CALLBACKS"); + jvmtiEventCallbacks callbacks; + (void) memset(&callbacks, 0, sizeof(callbacks)); + + LOG("SET JVMTI CLASS FILE LOAD HOOK"); + callbacks.ClassFileLoadHook = &ClassDecryptHook; + error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks)); + if (JVMTI_ERROR_NONE != error) { + printf("ERROR: Unable to SetEventCallbacks JVMTI!\n"); + return error; + } + LOG("SET EVENT NOTIFICATION MODE"); + error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); + if (JVMTI_ERROR_NONE != error) { + printf("ERROR: Unable to SetEventNotificationMode JVMTI!\n"); + return error; + } + + LOG("INIT JVMTI SUCCESS"); + return JNI_OK; +} \ No newline at end of file diff --git a/native/xxtea.c b/native/xxtea.c new file mode 100644 index 0000000..0fe5e2a --- /dev/null +++ b/native/xxtea.c @@ -0,0 +1,28 @@ +#include "xxtea_en.h" +#include "xxtea_de.h" + +void tea_encrypt(uint32_t *v, const uint32_t *k) { + uint32_t v0 = v[0], v1 = v[1], sum = 0, i; + uint32_t delta = 0x9e3779b9; + uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; + for (i = 0; i < 32; i++) { + sum += delta; + v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1); + v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3); + } + v[0] = v0; + v[1] = v1; +} + +void tea_decrypt(uint32_t *v, const uint32_t *k) { + uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i; + uint32_t delta = 0x9e3779b9; + uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; + for (i = 0; i < 32; i++) { + v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3); + v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1); + sum -= delta; + } + v[0] = v0; + v[1] = v1; +} \ No newline at end of file diff --git a/native/xxtea_common.c b/native/xxtea_common.c new file mode 100644 index 0000000..13f7c4a --- /dev/null +++ b/native/xxtea_common.c @@ -0,0 +1,16 @@ +#include "xxtea_common.h" + +unsigned int convert(const unsigned char *arr) { + unsigned int result = 0; + int i; + for (i = 0; i < 4; i++) { + result |= (arr[i] << (8 * i)); + } + return result; +} + +void revert(unsigned int value, unsigned char *arr) { + for (int i = 0; i < 4; i++) { + arr[i] = (value >> (8 * i)) & 0xFF; + } +} \ No newline at end of file diff --git a/native/xxtea_common.h b/native/xxtea_common.h new file mode 100644 index 0000000..20f5998 --- /dev/null +++ b/native/xxtea_common.h @@ -0,0 +1,8 @@ +#ifndef NATIVE_XXTEA_COMMON_H +#define NATIVE_XXTEA_COMMON_H + +#endif //NATIVE_XXTEA_COMMON_H + +unsigned int convert(const unsigned char *arr); + +void revert(unsigned int value, unsigned char *arr); \ No newline at end of file diff --git a/native/xxtea_de.h b/native/xxtea_de.h new file mode 100644 index 0000000..195e39f --- /dev/null +++ b/native/xxtea_de.h @@ -0,0 +1,11 @@ +#ifndef NATIVE_XXTEA_DE_H +#define NATIVE_XXTEA_DE_H + +#endif //NATIVE_XXTEA_DE_H + +#include "xxtea_common.h" + +#include +#include + +void tea_decrypt(uint32_t *v, const uint32_t *k); \ No newline at end of file diff --git a/native/xxtea_en.h b/native/xxtea_en.h new file mode 100644 index 0000000..7bd607a --- /dev/null +++ b/native/xxtea_en.h @@ -0,0 +1,11 @@ +#ifndef NATIVE_XXTEA_EN_H +#define NATIVE_XXTEA_EN_H + +#endif //NATIVE_XXTEA_EN_H + +#include "xxtea_common.h" + +#include +#include + +void tea_encrypt(uint32_t *v, const uint32_t *k); \ No newline at end of file diff --git a/native/xxtea_test.c b/native/xxtea_test.c new file mode 100644 index 0000000..78f8319 --- /dev/null +++ b/native/xxtea_test.c @@ -0,0 +1,39 @@ +#include "xxtea_en.h" +#include "xxtea_de.h" + +void printHex(const unsigned char *arr, int length) { + for (int i = 0; i < length; i++) { + printf("%02X", arr[i]); + } + printf("\n"); +} + +int main() { + unsigned char data1[] = {0xca, 0xfe, 0xba, 0xbe}; + printHex(data1, 4); + unsigned char data2[] = {0x01, 0x02, 0x03, 0x04}; + printHex(data2, 4); + uint32_t v[2] = {convert(data1), convert(data2)}; + + // key: Y4Sec-Team-4ra1n + // 59345365 632D5465 616D2D34 7261316E + + uint32_t const k[4] = { + (unsigned int) 0x65533459, (unsigned int) 0x65542d63, + (unsigned int) 0X342d6d61, (unsigned int) 0x6e316172, + }; + + printf("data: 0x%x 0x%x\n", v[0], v[1]); + tea_encrypt(v, k); + printf("encrypted: 0x%x 0x%x\n", v[0], v[1]); + tea_decrypt(v, k); + printf("decrypted: 0x%x 0x%x\n", v[0], v[1]); + + unsigned char first[4]; + unsigned char second[4]; + revert(v[0], first); + printHex(first, 4); + revert(v[1], second); + printHex(second, 4); + return 0; +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5b58da8 --- /dev/null +++ b/pom.xml @@ -0,0 +1,145 @@ + + + 4.0.0 + + org.y4sec + code-encryptor-plus + 0.0.1 + + + 8 + 8 + UTF-8 + + + + + + com.intellij + forms_rt + 7.0.3 + + + com.formdev + flatlaf + 3.0 + + + org.apache.logging.log4j + log4j-core + 2.20.0 + + + com.beust + jcommander + 1.82 + + + + + + + com.intellij + forms_rt + + + com.formdev + flatlaf + + + org.apache.logging.log4j + log4j-core + + + com.beust + jcommander + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + + org.apache.maven.plugins + maven-assembly-plugin + 3.6.0 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + + + + + org.apache.maven.plugins + maven-resources-plugin + + + org.apache.maven.plugins + maven-assembly-plugin + + + build-cli + + false + false + + + org.y4sec.encryptor.cli.Application + + + + jar-with-dependencies + + ${project.artifactId}-${project.version}-cli + + package + + single + + + + build-gui + + false + false + + + org.y4sec.encryptor.gui.GUIMain + + + + jar-with-dependencies + + ${project.artifactId}-${project.version}-gui + + package + + single + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${maven.compiler.source} + ${maven.compiler.target} + + -Xlint:none + + + + + + \ No newline at end of file diff --git a/script/README.md b/script/README.md new file mode 100644 index 0000000..0269c66 --- /dev/null +++ b/script/README.md @@ -0,0 +1,19 @@ +# script + +encrypt + +```shell + java -jar .\code-encryptor-plus-0.0.1-jar-with-dependencies.jar patch --jar .\fake-mysql-gui-0.0.3.jar --package me.n1ar4 +``` + +export + +```shell +java -jar .\code-encryptor-plus-0.0.1-jar-with-dependencies.jar export +``` + +run + +```shell +java -agentlib:D:\JavaCode\code-encryptor-plus\target\code-encryptor-plus-temp\decrypter=PACKAGE_NAME=me.n1ar4 -jar .\fake-mysql-gui-0.0.3_encrypted.jar +``` \ No newline at end of file diff --git a/src/main/java/org/y4sec/encryptor/cli/Application.java b/src/main/java/org/y4sec/encryptor/cli/Application.java new file mode 100644 index 0000000..a82581e --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/cli/Application.java @@ -0,0 +1,64 @@ +package org.y4sec.encryptor.cli; + +import com.beust.jcommander.JCommander; +import org.y4sec.encryptor.core.Constants; + + +public class Application implements Constants { + public static void main(String[] args) { + printLogo(); + // OS + String os = System.getProperty("os.name").toLowerCase(); + // ARCH + String bits = System.getProperty("sun.arch.data.model").toLowerCase(); + if (!os.contains("windows") || !bits.equals("64")) { + System.out.println("ONLY SUPPORT WINDOWS X64"); + System.out.printf("YOUR OS IS: %s - %s%n", os, bits); + return; + } + String javaVersion = System.getProperty("java.version"); + if (!javaVersion.startsWith("1.8")) { + System.out.println("ONLY SUPPORT JAVA 8"); + return; + } + + PatchCommand patchCommand = new PatchCommand(); + ExportCommand exportCommand = new ExportCommand(); + + JCommander jCommander = JCommander.newBuilder() + .addCommand(PatchCMD, patchCommand) + .addCommand(ExportCMD, exportCommand) + .build(); + + jCommander.parse(args); + + String command = jCommander.getParsedCommand(); + if (command == null) { + jCommander.usage(); + return; + } + + switch (command) { + case PatchCMD: + patchCommand.execute(); + break; + case ExportCMD: + exportCommand.execute(); + break; + default: + jCommander.usage(); + break; + } + } + + private static void printLogo() { + System.out.println("___________ __ \n" + + "\\_ _____/ ____ ___________ ___.__._______/ |_ ___________ \n" + + " | __)_ / \\_/ ___\\_ __ < | |\\____ \\ __\\/ _ \\_ __ \\\n" + + " | \\ | \\ \\___| | \\/\\___ || |_> > | ( <_> ) | \\/\n" + + "/_______ /___| /\\___ >__| / ____|| __/|__| \\____/|__| \n" + + " \\/ \\/ \\/ \\/ |__| "); + System.out.printf("Bytecode Encryptor Tool - version: %s\n", Version); + System.out.println("Powered By Y4Sec-Team"); + } +} diff --git a/src/main/java/org/y4sec/encryptor/cli/Command.java b/src/main/java/org/y4sec/encryptor/cli/Command.java new file mode 100644 index 0000000..3f8878a --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/cli/Command.java @@ -0,0 +1,5 @@ +package org.y4sec.encryptor.cli; + +public interface Command { + void execute(); +} diff --git a/src/main/java/org/y4sec/encryptor/cli/ExportCommand.java b/src/main/java/org/y4sec/encryptor/cli/ExportCommand.java new file mode 100644 index 0000000..c30ec99 --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/cli/ExportCommand.java @@ -0,0 +1,24 @@ +package org.y4sec.encryptor.cli; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.y4sec.encryptor.core.Constants; +import org.y4sec.encryptor.util.JNIUtil; + +@Parameters(commandDescription = "Export Command") +class ExportCommand implements Command, Constants { + private static final Logger logger = LogManager.getLogger(); + @Parameter(names = "--output", description = "Output File Path") + @SuppressWarnings("unused") + private String outputPath; + + public void execute() { + logger.info("execute export command"); + JNIUtil.extractDllSo(DecrypterDLL, outputPath, false); + System.out.println("----------- ADD VM OPTIONS -----------"); + System.out.println("java -agentlib:path-to-file=PACKAGE_NAME=xxx [other-params]"); + System.out.println("java -agentlib:encryptor=PACKAGE_NAME=org.y4sec -jar test.jar"); + } +} \ No newline at end of file diff --git a/src/main/java/org/y4sec/encryptor/cli/PatchCommand.java b/src/main/java/org/y4sec/encryptor/cli/PatchCommand.java new file mode 100644 index 0000000..27fb282 --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/cli/PatchCommand.java @@ -0,0 +1,33 @@ +package org.y4sec.encryptor.cli; + +import com.beust.jcommander.Parameter; +import com.beust.jcommander.Parameters; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.y4sec.encryptor.core.Constants; +import org.y4sec.encryptor.core.PatchHelper; +import org.y4sec.encryptor.util.JNIUtil; + +import java.nio.file.Path; +import java.nio.file.Paths; + +@Parameters(commandDescription = "Patch Command") +class PatchCommand implements Command, Constants { + private static final Logger logger = LogManager.getLogger(); + @Parameter(names = "--jar", description = "JAR File Path", required = true) + String jarPath; + @Parameter(names = "--package", description = "Encrypt Package Name", required = true) + String packageName; + + public void execute() { + logger.info("patch jar: {}",jarPath); + Path path = Paths.get(jarPath); + JNIUtil.extractDllSo(EncryptorDLL,null,true); + Path libPath = Paths.get(TempDir).resolve(EncryptorDLL); + if(packageName == null || packageName.isEmpty()){ + logger.error("need package name"); + return; + } + PatchHelper.patchJar(path,libPath,packageName); + } +} diff --git a/src/main/java/org/y4sec/encryptor/core/CodeEncryptor.java b/src/main/java/org/y4sec/encryptor/core/CodeEncryptor.java new file mode 100644 index 0000000..3bd7b60 --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/core/CodeEncryptor.java @@ -0,0 +1,14 @@ +package org.y4sec.encryptor.core; + +/** + * Code Encryptor use JNI + */ +public class CodeEncryptor { + /** + * Native Code Encrypt Method + * + * @param text ByteCode + * @return Encrypted BytesCode + */ + public native static byte[] encrypt(byte[] text, int length); +} diff --git a/src/main/java/org/y4sec/encryptor/core/Constants.java b/src/main/java/org/y4sec/encryptor/core/Constants.java new file mode 100644 index 0000000..d972fc4 --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/core/Constants.java @@ -0,0 +1,16 @@ +package org.y4sec.encryptor.core; + +public interface Constants { + String Version = "0.0.1"; + String DecrypterDLL = "decrypter.dll"; + String EncryptorDLL = "encryptor.dll"; + String TempDir = "code-encryptor-plus-temp"; + String NewFileSuffix = "encrypted"; + String DllFile = ".dll"; + String SOFile = ".so"; + String ClassFile = ".class"; + String WindowsOS = "windows"; + Integer BufSize = 16384; + String PatchCMD = "patch"; + String ExportCMD = "export"; +} diff --git a/src/main/java/org/y4sec/encryptor/core/PatchHelper.java b/src/main/java/org/y4sec/encryptor/core/PatchHelper.java new file mode 100644 index 0000000..7debe17 --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/core/PatchHelper.java @@ -0,0 +1,94 @@ +package org.y4sec.encryptor.core; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.y4sec.encryptor.util.JNIUtil; + +import java.io.*; +import java.lang.reflect.Field; +import java.nio.file.Path; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.zip.ZipOutputStream; + +public class PatchHelper implements Constants { + private static final Logger logger = LogManager.getLogger(); + + @SuppressWarnings("unchecked") + public static void patchJar(Path jarPath, Path libPath, String packageName) { + logger.info("start patch jar"); + + JNIUtil.loadLib(libPath.toAbsolutePath().toString()); + packageName = packageName.replaceAll("\\.", "/"); + + try { + File srcFile = jarPath.toFile(); + String srcName = srcFile.getName(); + String outputFileName = String.format("%s_%s.jar", + srcName.substring(0, srcName.lastIndexOf(".")), NewFileSuffix); + File dstFile = new File(outputFileName); + + FileOutputStream dstFos = new FileOutputStream(dstFile); + JarOutputStream dstJar = new JarOutputStream(dstFos); + + JarFile srcJar = new JarFile(srcFile); + byte[] buf = new byte[1024]; + + ByteArrayOutputStream bao = new ByteArrayOutputStream(); + Enumeration enumeration = srcJar.entries(); + + while (enumeration.hasMoreElements()) { + JarEntry entry = enumeration.nextElement(); + InputStream is = srcJar.getInputStream(entry); + int len; + while ((len = is.read(buf, 0, buf.length)) != -1) { + bao.write(buf, 0, len); + } + byte[] bytes = bao.toByteArray(); + + String name = entry.getName(); + if (name.startsWith(packageName)) { + if (name.toLowerCase().endsWith(ClassFile)) { + try { + bytes = CodeEncryptor.encrypt(bytes, bytes.length); + } catch (Exception e) { + logger.error("encrypt error: {}", e.toString()); + return; + } + } + } + + JarEntry ne = new JarEntry(name); + + try { + dstJar.putNextEntry(ne); + + // allow duplicate entry + // https://stackoverflow.com/questions/39958486/ + Field namesField = ZipOutputStream.class.getDeclaredField("names"); + namesField.setAccessible(true); + Object obj = namesField.get(dstJar); + HashSet names = (HashSet) obj; + names.remove(name); + + dstJar.write(bytes); + } catch (Exception z) { + logger.warn("put entry: {}", z.toString()); + } + bao.reset(); + } + + srcJar.close(); + dstJar.close(); + dstFos.close(); + + logger.info("encrypt finished"); + logger.info("output file: {}", outputFileName); + } catch (Exception e) { + logger.error("patch error: {}", e.toString()); + } + } +} diff --git a/src/main/java/org/y4sec/encryptor/gui/GUIMain.java b/src/main/java/org/y4sec/encryptor/gui/GUIMain.java new file mode 100644 index 0000000..c06d8de --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/gui/GUIMain.java @@ -0,0 +1,10 @@ +package org.y4sec.encryptor.gui; + +import com.formdev.flatlaf.FlatDarkLaf; + +public class GUIMain { + public static void main(String[] args) { + FlatDarkLaf.setup(); + MainForm.start(); + } +} diff --git a/src/main/java/org/y4sec/encryptor/gui/MainForm.form b/src/main/java/org/y4sec/encryptor/gui/MainForm.form new file mode 100644 index 0000000..dc33490 --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/gui/MainForm.form @@ -0,0 +1,127 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/org/y4sec/encryptor/gui/MainForm.java b/src/main/java/org/y4sec/encryptor/gui/MainForm.java new file mode 100644 index 0000000..70fd538 --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/gui/MainForm.java @@ -0,0 +1,155 @@ +package org.y4sec.encryptor.gui; + +import com.intellij.uiDesigner.core.GridConstraints; +import com.intellij.uiDesigner.core.GridLayoutManager; +import org.y4sec.encryptor.core.Constants; +import org.y4sec.encryptor.core.PatchHelper; +import org.y4sec.encryptor.util.JNIUtil; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; +import java.awt.*; +import java.io.File; +import java.io.PrintStream; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class MainForm implements Constants { + private JPanel masterPanel; + private JPanel rootPanel; + private JTextField jarText; + private JButton choseFileButton; + private JTextField packageText; + private JButton encryptJarFileButton; + private JButton exportAgentLibButton; + private JPanel logPanel; + private JScrollPane scroll; + private JTextArea logArea; + private JLabel jarLabel; + private JLabel packageLabel; + private JLabel operationLabel; + private JPanel operationPanel; + + public static void start() { + JFrame frame = new JFrame("code-encryptor-plus"); + frame.setContentPane(new MainForm().masterPanel); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + frame.setResizable(false); + } + + private void log(String data) { + String msg = String.format("[log] %s\n", data); + logArea.append(msg); + logArea.setCaretPosition(logArea.getText().length()); + } + + public MainForm() { + log("start code encryptor success"); + choseFileButton.addActionListener(e -> { + log("chose jar file operation"); + JFileChooser fileChooser = new JFileChooser(); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.setAcceptAllFileFilterUsed(false); + File workingDirectory = new File(System.getProperty("user.dir")); + fileChooser.setCurrentDirectory(workingDirectory); + FileNameExtensionFilter filter = new FileNameExtensionFilter("JAR", "jar"); + fileChooser.addChoosableFileFilter(filter); + int option = fileChooser.showOpenDialog(new JFrame()); + if (option == JFileChooser.APPROVE_OPTION) { + File file = fileChooser.getSelectedFile(); + String absPath = file.getAbsolutePath(); + jarText.setText(absPath); + } + }); + + encryptJarFileButton.addActionListener(e -> { + String packageName = packageText.getText(); + if (packageName == null || packageName.isEmpty()) { + log("package is null"); + return; + } + String jar = jarText.getText(); + if (jar == null || jar.isEmpty()) { + log("jar is null"); + return; + } + new Thread(() -> { + JNIUtil.extractDllSo(EncryptorDLL, null, true); + Path libPath = Paths.get(TempDir).resolve(EncryptorDLL); + PatchHelper.patchJar(Paths.get(jar), libPath, packageName); + }).start(); + }); + + exportAgentLibButton.addActionListener(e -> { + JNIUtil.extractDllSo(DecrypterDLL, null, false); + JOptionPane.showMessageDialog(rootPanel, + "File: " + TempDir + "/" + "decrypter.dll"); + }); + } + + { +// GUI initializer generated by IntelliJ IDEA GUI Designer +// >>> IMPORTANT!! <<< +// DO NOT EDIT OR ADD ANY CODE HERE! + $$$setupUI$$$(); + } + + /** + * Method generated by IntelliJ IDEA GUI Designer + * >>> IMPORTANT!! <<< + * DO NOT edit this method OR call it in your code! + * + * @noinspection ALL + */ + private void $$$setupUI$$$() { + masterPanel = new JPanel(); + masterPanel.setLayout(new GridLayoutManager(2, 1, new Insets(0, 0, 0, 0), -1, -1)); + rootPanel = new JPanel(); + rootPanel.setLayout(new GridLayoutManager(3, 3, new Insets(0, 0, 0, 3), -1, -1)); + masterPanel.add(rootPanel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + jarLabel = new JLabel(); + jarLabel.setText("Jar File"); + rootPanel.add(jarLabel, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 1, false)); + jarText = new JTextField(); + rootPanel.add(jarText, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + choseFileButton = new JButton(); + choseFileButton.setText("Chose File"); + rootPanel.add(choseFileButton, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + packageLabel = new JLabel(); + packageLabel.setText("Package Name"); + rootPanel.add(packageLabel, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 1, false)); + packageText = new JTextField(); + rootPanel.add(packageText, new GridConstraints(1, 1, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension(150, -1), null, 0, false)); + operationLabel = new JLabel(); + operationLabel.setText("Operation"); + rootPanel.add(operationLabel, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 1, false)); + operationPanel = new JPanel(); + operationPanel.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1)); + rootPanel.add(operationPanel, new GridConstraints(2, 1, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + encryptJarFileButton = new JButton(); + encryptJarFileButton.setText("Encrypt Jar File"); + operationPanel.add(encryptJarFileButton, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + exportAgentLibButton = new JButton(); + exportAgentLibButton.setText("Export Agent Lib"); + operationPanel.add(exportAgentLibButton, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); + logPanel = new JPanel(); + logPanel.setLayout(new GridLayoutManager(1, 1, new Insets(3, 3, 3, 3), -1, -1)); + masterPanel.add(logPanel, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, new Dimension(500, 200), new Dimension(500, 200), new Dimension(500, 200), 0, false)); + scroll = new JScrollPane(); + logPanel.add(scroll, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); + logArea = new JTextArea(); + logArea.setEditable(false); + logArea.setForeground(new Color(-16722419)); + scroll.setViewportView(logArea); + } + + /** + * @noinspection ALL + */ + public JComponent $$$getRootComponent$$$() { + return masterPanel; + } + +} diff --git a/src/main/java/org/y4sec/encryptor/util/ByteUtil.java b/src/main/java/org/y4sec/encryptor/util/ByteUtil.java new file mode 100644 index 0000000..b444fd0 --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/util/ByteUtil.java @@ -0,0 +1,25 @@ +package org.y4sec.encryptor.util; + +/** + * hex string < - > byte array + */ +@SuppressWarnings("unused") +public class ByteUtil { + public static byte[] hexStringToByteArray(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } + return data; + } + + public static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02X", b)); + } + return sb.toString(); + } +} diff --git a/src/main/java/org/y4sec/encryptor/util/JNIUtil.java b/src/main/java/org/y4sec/encryptor/util/JNIUtil.java new file mode 100644 index 0000000..e084e5c --- /dev/null +++ b/src/main/java/org/y4sec/encryptor/util/JNIUtil.java @@ -0,0 +1,138 @@ +package org.y4sec.encryptor.util; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.y4sec.encryptor.core.Constants; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * JNI Utils + */ +public class JNIUtil implements Constants { + private static final Logger logger = LogManager.getLogger(); + private static final String lib = "java.library.path"; + + /** + * Make new JNI lib effective + * + * @return success or not + */ + @SuppressWarnings("all") + private static boolean deleteUrls() { + try { + final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths"); + sysPathsField.setAccessible(true); + sysPathsField.set(null, null); + return true; + } catch (Exception ex) { + logger.error("delete classloader sys_paths error: {}", ex.toString()); + } + return false; + } + + /** + * Load JNI lib + * + * @param path dll/so path + * @return success or not + */ + public static boolean loadLib(String path) { + Path p = Paths.get(path); + if (!Files.exists(p)) { + logger.error("load lib error: file not found"); + return false; + } + if (Files.isDirectory(p)) { + logger.error("load lib error: input file is a dir"); + return false; + } + String os = System.getProperty("os.name").toLowerCase(); + String libDirAbsPath = Paths.get(p.toFile().getParent()).toAbsolutePath().toString(); + String originLib = System.getProperty(lib); + if (os.contains(WindowsOS)) { + originLib = originLib + String.format(";%s;", libDirAbsPath); + System.setProperty(lib, originLib); + if (!deleteUrls()) { + return false; + } + String dll = p.toFile().getName().toLowerCase(); + if (!dll.endsWith(DllFile)) { + logger.error("load lib error: must be a dll file"); + return false; + } + String file = dll.split("\\.dll")[0].trim(); + logger.info("load library: " + file); + System.loadLibrary(file); + } else { + originLib = originLib + String.format(":%s:", libDirAbsPath); + System.setProperty(lib, originLib); + if (!deleteUrls()) { + return false; + } + String so = p.toFile().getName().toLowerCase(); + if (!so.endsWith(SOFile)) { + logger.error("must be a so file"); + return false; + } + String file = so.split("\\.so")[0].trim(); + logger.info("load library: " + file); + System.loadLibrary(file); + } + return true; + } + + /** + * Write dll/so file to temp directory and load it + * + * @param filename dll/so file name in resources + */ + public static void extractDllSo(String filename,String dir,boolean load) { + InputStream is = null; + try { + is = JNIUtil.class.getClassLoader().getResourceAsStream(filename); + if (is == null) { + logger.error("error dll name"); + return; + } + if(dir==null || dir.isEmpty()){ + dir = TempDir; + } + Path dirPath = Files.createDirectories(Paths.get(dir)); + Path outputFile = dirPath.resolve(filename); + + if (!Files.exists(outputFile)) { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] data = new byte[BufSize]; + while ((nRead = is.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, nRead); + } + Files.write(outputFile, buffer.toByteArray()); + logger.info("write file: " + outputFile.toAbsolutePath()); + } + if(load) { + boolean success = loadLib(outputFile.toAbsolutePath().toString()); + if (!success) { + logger.error("load lib failed"); + } + } + } catch (Exception ex) { + logger.error("extract file error: {}", ex.toString()); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + logger.error("close stream error: {}", e.toString()); + } + } + } + } +} diff --git a/src/main/resources/decrypter.dll b/src/main/resources/decrypter.dll new file mode 100644 index 0000000000000000000000000000000000000000..d8f837c2fafb3525b9f1745eb97d32b2466b7fd3 GIT binary patch literal 13312 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 P_9TB2OrKx>?>z9I6HZ!j literal 0 HcmV?d00001 diff --git a/src/main/resources/encryptor.dll b/src/main/resources/encryptor.dll new file mode 100644 index 0000000000000000000000000000000000000000..ff9bc1c66db7fbd2c2087722d285d5e1cb247363 GIT binary patch literal 11776 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 b_`&i+{7~bejfYwewI8BY|MdC)=7E0)Iqi+} literal 0 HcmV?d00001 diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..cef337e --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file