Commit 0630f7eb by sikang

move script

parent 56374043
{
"//root":"project根目录, 运行目录下的相对路径 或 绝对路径",
"root" : "../..",
"//lib_main":"所有加入混淆的library main目录. 'root' 下的相对路径",
"lib_main":[
"app/src/main",
"lib_base/src/main"
],
"//proguard":"所有用到的proguard-rules.pro 路径",
"proguard":[
"app/proguard-rules.pro",
"lib_base/proguard-rules.pro"
],
"//api_mapping":"api混淆文件的路径. 'root' 下的相对路径",
"api_mapping":"script/api_mapping",
"//string_encryption": "字符串加密方式,为false时,只做插入不做加密,未集成Philology填false",
"string_encryption" : "true",
"//image_garble":"是否混淆图片,修改图片MD5时可能会导致图片变色,出现这种情况先设为false",
"image_garble":"true",
"//activities":"需要混淆的类名,匹配方式 endswith() ,如 加入Activity.java 则所有Activity结尾的类加入混淆",
"activities" : [
"Activity.java",
"View.java",
"Layout.java",
"Bean.java",
"Fragment.java",
"Receiver.java",
"CertifyActiviy.java",
"BaseApplication.java",
"ContactEntity.java",
"SmsEntity.java",
"ActivityCenter.java",
"Service.java",
"Collector.java",
"BannerMessageDto.java",
"BasicAck.java",
"InviteResult.java",
"LoanAppBeanFatherStatusLogs.java",
"LoanRange.java",
"PhotoInfo.java",
"IncomeMessageProto.java",
"ResponseErrorBody.java",
"RecordFilesResponse.java",
"TotalAmount.java",
"UserBankInfo.java",
"YWUser.java",
"CountDownButton.java",
"ProgressDialog.java",
"LoadingDialog.java",
"MarqueeView.java",
"FloatView.java",
"SpanButton.java",
"TitleSpan.java",
"TopBar.java"
],
"//ignore_files":"在插入乱码时,要忽略的文件",
"ignore_files":[
"UploadCollectionBean.java"
],
"//ignore_layout":"布局混淆时,要跳过的layout,没有自定义layout可以忽略",
"ignore_layout":[
"TitleSpan",
"TopBar",
"SpanButton"
],
"//jiagu_output" : "360加固输出路径",
"jiagu_output" : "/Users/connor/Documents/apks",
"//jiagu_account" : "360加固 账号",
"jiagu_account" : "15902141504",
"//jiagu_pwd" : "360加固 密码",
"jiagu_pwd" : "qwqw10010",
"//jiagu_jar" : "jiagu.jar路径",
"jiagu_jar" : "/Users/connor/Documents/resources/app/jiagubao/jiagu/jiagu.jar"
}
\ No newline at end of file
# -*-coding:utf-8-*-
from tools.screen_maker import ScreenMaker
from PIL import Image
import random
import sys
import os
import io
import re
import shutil
import requests
import json
import chardet
class Function:
# 随机生成包名
def new_appid(self,config):
app_name = config['app_name'].replace(" ", "").lower()
start_name = ["com", "cn", "id", "app", "host", "in"]
middle_name = ["android", "main", "home", "base", "play", "release", "full", "kredit", "cepat",
"saku", "wallet", "coin", "loan", "flash", "pjnm", "indo", "lib"]
# start
pkg_name = start_name[random.randint(
0, len(start_name) - 1)] + "." + app_name
# middle
length = random.randint(1, 3)
for i in range(0, length):
pkg_name += "." + \
middle_name[random.randint(0, len(middle_name) - 1)]
# end
random_str = ''.join(random.sample(
"abcdefghijklmnopqrstuvwxyz", random.randint(4, 8)))
pkg_name += "." + random_str
version_code = str(int(config['version_code'])+1)
version_name = "#%s#"% version_code.replace("",".")
version_name = version_name.replace("#.","").replace(".#","")
lines = {
"app_id": pkg_name,
"version_code": version_code,
"version_name": version_name
}
self.update_properties(config,lines)
# 加载shell变量
def load_properties(self,path):
with open(path, "r", encoding="utf-8") as f:
lines = f.readlines()
config = {}
for line in lines:
if "=" in line:
key = line.split("=")[0].replace("\"","").replace("\'","").replace("\n","")
value = line.split("=")[1].replace("\"","").replace("\'","").replace("\n","")
config[key] = value
return config
# 创建签名文件
def new_keystore(self,config):
# 只保留最近10个签名
count = 0
for root, dirs, files in os.walk(config['jks_path']):
for name in files:
count += 1
if count > 10:
os.remove(os.path.join(root, name))
# 创建签名文件
key_name = config['app_name'].replace(" ", "")+config['version_code']
command = "keytool -genkey" + " -alias <key_name> -keypass <key_name> -storepass <key_name>" \
+ " -dname \"CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown\"" \
+ " -keyalg RSA -validity 20000 -keystore <path>/<key_name>.keystore"
command = command.replace("<key_name>", key_name).replace(
"<path>", config["jks_path"])
os.system(command)
# 更新签名配置
jks_path = "../jks/%s.keystore" % key_name
reset = {
"signing_keyAlias": key_name,
"signing_certificate": jks_path,
"signging_certificatePassword": key_name,
"signging_storePassword": key_name,
}
self.update_properties(config, reset)
config['signing_certificate'] = jks_path
config['signging_storePassword'] = key_name
self.upate_keytore_sign(config)
def upate_keytore_sign(self,config):
jks_path= "%s/jks/%s"%(config['root'],config['signing_certificate'].split("/")[2])
output = os.popen("keytool -list -v -keystore %s -keypass %s -storepass %s"% (jks_path,config['signging_storePassword'],config['signging_storePassword']))
sha1 = output.read().split("SHA1:")[1].split("SHA256")[0].replace(" ","").replace("\n","").replace("\t","")
self.update_properties(config, {"keystore_sign":"\"%s\""%sha1})
# 更新properties字段
def update_properties(self,config, dict):
file_content = ""
replace_line = {}
with open("%s/gradle.properties"%config['root'], "r", encoding="utf-8") as f:
file_content = f.read()
for key in dict.keys():
info = re.compile(r''+key+"=(.*)\n")
result = info.search(file_content)
if result is not None:
targetLine = result.group()
newLine = "%s=%s\n" % (key, dict[key])
replace_line[targetLine] = newLine
else:
print("%s 字段不存在 !!!"%key)
for key in replace_line.keys():
print(replace_line[key].replace("\n", ""))
file_content = file_content.replace(key, replace_line[key])
with open("%s/gradle.properties"%config['root'], "w", encoding="utf-8") as f_w:
f_w.write(file_content)
# 移动apk
def move_apk(self,config):
file_name = "%s_%s" % (
config['corp_id'], config['app_name'].replace(" ", "_"))
apk_local = "%s/resGuardApks/%s_release.apk" % (
config['root'], file_name)
apk1 = "/Users/connor/Documents/apks/%s.apk" % file_name
apk2 = "/Users/connor/Documents/apks/%s/%s.apk" % (
file_name, file_name)
if os.path.exists("/Users/connor/Documents/apks/%s" % file_name):
shutil.copy(apk_local, apk2)
else:
shutil.copy(apk_local, apk1)
# FB秘钥散列
def getFbSign(self,config):
with open("%s/app/src/main/AndroidManifest.xml" % config['root'], "r") as f:
file_content = f.read()
info = re.compile(r'package=\"(.*)\"')
package = info.search(file_content).group().split("=")[
1].replace("\"", "")
info = re.compile(r'\"(.*).SplashActivity\"')
package += info.search(file_content).group().replace("\"", "")
print("包名:" + config['app_id'])
print("类名:" + package)
print("散列:")
command = "keytool -exportcert -alias <signing_keyAlias> -keystore app/<signing_certificate> -storepass <signing_keyAlias> | openssl sha1 -binary | openssl base64"
command = command.replace("<signing_keyAlias>", config['signing_keyAlias'])\
.replace("<signing_certificate>", config['signing_certificate'])
os.system(command)
# 更新Gateway
def update_gateway(self,config):
gateway = requests.get(config['gateway_url']).json()
jsonStr = json.dumps(gateway).replace("http://", "https://")
gateway = json.loads(jsonStr)
ip = gateway['gateway'][0]
if len(gateway['gateway']) > 1:
ip = gateway['gateway'][1]
harvest = gateway['harvester'][0].replace("https://","")
replaces = {
"base_url": "\"%s\"" % gateway['rest'][0],
"harvest_ip": "\"%s\"" % harvest.split(":")[0],
"harvest_port": "%s" % harvest.split(":")[1],
"gateway_url": "\"%s\"" % gateway['gateway'][0],
"gateway_ip": "\"%s\"" % ip,
"repayment_h5": "\"%s\"" % gateway['repay'][0],
"admin_host": "\"%s\"" % gateway['admin'][0],
"agreement_url": "\"%s\"" % gateway['privacy'][0],
"home": "\"%s\"" % gateway['home'][0],
}
self.update_properties(config, replaces)
# 切换主包马甲包
def cutover(self,config):
print("1、切换到主包")
print("2、切换到马甲包")
img_path = "%s/app/src/main/res/drawable-xxhdpi/" % config['root']
command = int(input("选择包类型:"))
if command == 1:
shutil.copy(img_path+"logo_main.png", img_path+"logo.png")
# 主包混淆文件
if os.path.exists("%s/script/api_mapping" % config['root']):
os.remove("%s/script/api_mapping" % config['root'])
shutil.copy("%s/script/api_mapping_main" %
config['root'], "%s/script/api_mapping" % config['root'])
replace_lines = {
"app_name": config['main_name'],
"gateway_url": "\"%s\"" % config['gateway_main'],
"host_app": "true"
}
config['gateway_url'] = config['gateway_main']
# 更新gw
self.update_properties(config, replace_lines)
self.update_gateway(config)
elif command == 2:
shutil.copy(img_path+"logo_majia.png", img_path+"logo.png")
# 马甲混淆文件替换
if os.path.exists("%s/script/api_mapping" % config['root']):
os.remove("%s/script/api_mapping" % config['root'])
shutil.copy("%s/script/api_mapping_majia" %
config['root'], "%s/script/api_mapping" % config['root'])
replace_lines = {
"app_name": config['majia_name'],
"gateway_url": "\"%s\"" % config['gateway_mj'],
"host_app": "false"
}
config['gateway_url'] = config['gateway_mj']
# 更新gw
self.update_properties(config, replace_lines)
self.update_gateway(config)
# 创建描述文件
def create_desc(self,config):
desc = ""
with open("/Users/connor/StudioProjects/WorkSpace/app_desc.txt", "r") as f:
file_content = f.read().replace("\n", "--line--")
index = random.randint(1, 42)
print("模板%d"%index)
info = re.compile(
r''+"@Example %d--line--(.*)@End %d" % (index, index))
desc = info.search(file_content).group()
desc = desc.replace("--line--", "\n")\
.replace("@Example %d\n" % index, "")\
.replace("@End %d" % index, "")
file_name = "%s_%s"\
% (config['corp_id'], config['app_name'].replace(" ", "_"))
output = "/Users/connor/Documents/apks/%s/%s.txt" % (
file_name, file_name)
with open(output, "w+") as f_w:
desc = desc.replace("${email}", config['cus_email'])\
.replace("${app_name}", config['app_name'])\
.replace("${phone_num}", config['hot_line'])\
.replace("${address}", config['cus_adress'])
f_w.write(desc)
# 打印checklist
def print_checklist(self,config, just_print):
print(" ")
print("%s %s" % (config['corp_id'], config['app_name']))
print("包名:%s" % config['app_id'])
print("对内协议:%s" % config['agreement_url'])
print("对外协议:%s/privacy.html" % config['home'])
print(" ")
if just_print:
return
file_name = "%s_%s"\
% (config['corp_id'], config['app_name'].replace(" ", "_"))
target = "/Users/connor/Documents/apks"
img_path = "../../app/src/main/res/drawable-xxhdpi"
if not os.path.exists(target+"/"+file_name):
os.makedirs(target+"/"+file_name)
self.create_desc(config)
try:
shutil.move("%s/%s.apk" % (target, file_name),
"%s/%s/%s.apk" % (target, file_name, file_name))
shutil.move("%s/%s.html" % (target, file_name),
"%s/%s/%s.html" % (target, file_name, file_name))
except:
print("没有找到 apk 或 隐私协议 文件")
shutil.copy("%s/logo.png" % img_path, "%s/%s/logo.png" %
(target, file_name))
shutil.copy("%s/top.png" % img_path, "%s/%s/top.png" %
(target, file_name))
screen = ScreenMaker()
screen.draw_bg(img_path+"/bg01.png", img_path+"/logo.png",
img_path+"/top.png", "/Users/connor/Documents/apks/"+file_name)
print("截图制作完成")
# 更新本地隐私协议
def update_local_privacy(self,config):
path = config['root'] + "/app/src/main/assets/web/"
if not os.path.exists(path):
os.makedirs(path)
resp = requests.get(config['agreement_url'])
content = resp.text
encode = chardet.detect(resp.content)['encoding']
with io.open(path+"privacy.html", "w+", encoding=encode) as fout:
fout.write(content)
print("本地协议已更新!" + config['agreement_url'])
ksp_url = config['agreement_url'].replace(".html", "Ksp.html")
resp = requests.get(ksp_url)
content = resp.text
encode = chardet.detect(resp.content)['encoding']
if "<Code>NoSuchKey</Code>" not in content:
with io.open(path+"privacyKsp.html", "w+", encoding=encode) as fout:
fout.write(content)
print("本地KSP协议已更新!" + ksp_url)
# 创建新协议
def new_privacy(self,config):
permissions = "12356"
if config['contact'] != "true":
permissions = "2356"
file_name = "%s_%s" % (config['corp_id'], config['app_name'].replace(" ","_"))
print("path url: %s/privacy1.html" % config['home'])
with open("/Users/connor/Documents/apks/privacy/privacy0.html", "rt") as fin:
file_content = fin.read()
file_content = file_content.replace("${app_name}", config['app_name'])
file_content = file_content.replace("${permission_list}", permissions)
with open("/Users/connor/Documents/apks/%s.html" % file_name, "wt") as fout:
fout.write(file_content)
print("privacy done\n")
# 转移出所有素材
def move_resources(self,config):
target = "/Users/connor/Documents/apks"
img_path = "../../app/src/main/res/drawable-xxhdpi"
if not os.path.exists(target+"/cache"):
os.makedirs(target+"/cache")
else:
shutil.rmtree(target+"/cache")
os.makedirs(target+"/cache")
# 移除
shutil.copy("%s/logo.png" % img_path, "%s/cache/logo.png" % target)
try:
shutil.copy("%s/top.png" % img_path, "%s/cache/top.png" % target)
shutil.copy("%s/script/api_mapping" %
config['root'], "%s/cache/api_mapping" % target)
except:
print("out: no api_mapping or img")
new_config = config.copy()
new_config.update(self.load_properties("../../gradle.properties"))
os.system("cd %s\ngit reset --hard origin/%s" % (config['root'],config['git_branch']))
# 还原
shutil.copy("%s/cache/logo.png" % target, "%s/logo.png" % img_path)
try:
os.remove("%s/script/api_mapping" % config['root'])
except:
print("")
try:
shutil.copy("%s/cache/top.png" % target, "%s/top.png" % img_path)
shutil.copy("%s/cache/api_mapping" %
target, "%s/script/api_mapping" % config['root'])
except:
print("in: no api_mapping or img")
self.update_gateway(new_config)
lines = {
"app_id": "%s" % new_config['app_id'],
"app_name": "%s" % new_config['app_name'],
"signing_keyAlias": "%s" % new_config['signing_keyAlias'],
"signing_certificate": "%s" % new_config['signing_certificate'],
"signging_certificatePassword": "%s" % new_config['signging_certificatePassword'],
"signging_storePassword": "%s" % new_config['signging_storePassword'],
}
self.update_properties(config, lines)
def crop_logo(self,config):
img_avg = Image.open("/Users/connor/Documents/apks/%s.png"%config['corp_id'])
logo_h = img_avg.size[1] * (512/img_avg.size[0])
top_h = img_avg.size[1] * (1024/img_avg.size[0])
img_logo = img_avg.resize((512, int(logo_h)),Image.ANTIALIAS)
img_top = img_avg.resize((1024, int(top_h)),Image.ANTIALIAS)
# 裁切图片
img_logo = img_logo.crop((0, (logo_h - 512)/2, img_logo.size[0], 512 + (logo_h - 512)/2))
img_top = img_top.crop((0, (top_h - 500)/2, img_top.size[0], 500+(top_h - 500)/2))
img_logo.save("%s/app/src/main/res/drawable-xxhdpi/logo_majia.png"% config['root'],"PNG")
img_top.save("%s/app/src/main/res/drawable-xxhdpi/top.png"% config['root'],"PNG")
print("done")
#copy logo
def find_logo(self,config):
path = "/Users/connor/Downloads/%s"%config['corp_id']
targets = {}
for root, dirs, files in os.walk(path):
for file in files:
if "logo_512" in file and "logo" not in targets.keys():
targets['logo'] = os.path.join(root,file)
if "1024" in file and "top" not in targets.keys():
targets['top'] = os.path.join(root,file)
img_path = "%s/app/src/main/res/drawable-xxhdpi"%config['root']
print(targets)
shutil.copy(targets['logo'], "%s/logo_majia.png" % img_path)
shutil.copy(targets['top'], "%s/top.png" % img_path)
print("done")
import json
from tools.garble.activity_garble import ActivityGarble
from tools.garble.api_garble import ApiGarble
from tools.garble.manifest_grable import ManifestGarble
from tools.garble.package_garble import PackageGarble
from tools.garble.string_garble import StringGarble
from tools.garble.img_garble import ImageGarble
from tools.garble.java_garble import JavaGarble
from tools.garble.layout_garble import LayoutGarble
from func import Function
import os
#读取config.json配置
config_json = {}
with open("config.json", "r", encoding="utf-8") as fin:
config_json = json.loads(fin.read())
#加入properties配置
properties = Function().load_properties("%s/gradle.properties"%config_json['root'])
config = config_json.copy()
config.update(properties)
print(" ")
print("------------- 使用帮助(混淆完一定要全流程测试) -----------------")
print("0、一条龙混淆")
print("1、activity类名混淆(支持kotlin,没测试过)")
print("2、api混淆(针对 Retrofit 注解)")
print("3、manifest混淆 在包路径中随机插入Activity并注册")
print("4、包路径混淆(支持kotlin,没测试过)")
print("5、字符串插入/加密")
print("6、图片混淆(修改md5 & 创建随机图片,体积会增加1-2M)")
print("7、java文件插入乱码(慎用,必须全流程测试)")
print("8、layout 混淆")
print("21、还原代码")
print(" ")
command = int(input("请输入指令编号:"))
if command == 0:
#布局文件混淆 必须放前面
LayoutGarble().layout_garble(config)
#Manifest混淆
ManifestGarble().manifest_garble(config)
#插入java乱码 必须放前面
JavaGarble().java_garble(config)
#四大组件类名混淆
ActivityGarble().activity_garble(config)
#包路径混淆
PackageGarble().pkg_garble(config)
#Api混淆
ApiGarble().api_garble(config)
#字符串混淆
StringGarble().str_grable(config)
#图片混淆
ImageGarble().img_garble(config)
elif command == 1:
#配置参数 config.json - activities
ActivityGarble().activity_garble(config)
elif command == 2:
ApiGarble().api_garble(config)
elif command == 3:
#注意: src/main/java 目录下,只能是目录,不可以有文件
# 如果使用了 cash_plugin_toolbox ,需要更新一下,确保 Manifest 中有 <application> 标签
ManifestGarble().manifest_garble(config)
elif command == 4:
#所有library src/main/java 下的包名混淆
PackageGarble().pkg_garble(config)
elif command == 5:
StringGarble().str_grable(config)
elif command == 6:
ImageGarble().img_garble(config)
elif command == 7:
JavaGarble().java_garble(config)
elif command == 8:
LayoutGarble().layout_garble(config)
elif command == 21:
#每行一个shell命令,参考自行修改
command = "%s\n%s\n%s\n%s\n%s\n%s\n" \
% (
"cd %s" % config['root'],
"git checkout . && git clean -df",
"git reset --hard origin/%s" % config['git_branch'],
"cd lib_base || { echo \"lib_base not exist!\"; exit 1; }",
"git checkout . && git clean -df",
"git reset --hard origin/master"
)
os.system(command)
# -*-coding:utf-8-*-
from func import Function
from shell import Shell
from tools.garble.api_garble import ApiGarble
from tools.garble.activity_garble import ActivityGarble
from tools.garble.string_garble import StringGarble
from tools.garble.package_garble import PackageGarble
from tools.garble.manifest_grable import ManifestGarble
from tools.garble.img_garble import ImageGarble
from tools.sdk_manager import SdkManager
from tools.garble.java_garble import JavaGarble
from tools.garble.layout_garble import LayoutGarble
import os
import shutil
import json
config_json = {}
with open("config.json", "r", encoding="utf-8") as fin:
config_json = json.loads(fin.read())
properties = Function().load_properties("%s/gradle.properties"%config_json['root'])
config = config_json.copy()
config.update(properties)
config['jks_path'] = "../../jks"
config['apk_path'] = "../../resGuardApks/%s_%s_release.apk" % (
config["corp_id"], config["app_name"].replace(" ", "_"))
print(" ")
print("------------- 使用帮助 -----------------")
print("1、编译apk")
print("2、修改包名,版本号+1")
print("3、创建新的签名文件")
print("4、commit & push project")
print("5、pull lib_base")
print("6、commit & push lib_base")
print("7、获取签名秘钥散列")
print("8、提交一个渠道包Tag")
print("9、还原某一次提交的包名、logo、gw、name、但保持最新代码")
print("10、更新Gateway")
print("11、copy apk")
print("12、马甲包切换")
print("13、打印checklist")
print("14、生成隐协议文件")
print("15、刷新本地协议")
print("16、api混淆")
print("17、字符串混淆")
print("18、四大组件混淆")
print("19、包路径混淆")
print("20、插入Activity")
print("21、reset project")
print("22、加固")
print("23、插入混淆图片")
print("24、插入混淆代码")
print("25、插入混淆layout")
print("26、启用/禁用代码")
print("27、签名SHA1")
print("121、安装apk到手机")
print("122、裁切脚本logo和置顶图")
print("123、替换设计图")
command = int(input("请输入指令编号:"))
# 命令
if command == 1 or command == 111:
# 注释通话记录代码
SdkManager().start_process(config, False, "NOLOG")
# 注释/开启 通讯录代码
if config['contact'] == "true":
SdkManager().start_process(config, True, "CONTACT")
else:
SdkManager().start_process(config, False, "CONTACT")
# 布局文件混淆
LayoutGarble().layout_garble(config)
# api混淆
ApiGarble().api_garble(config)
# 字符串混淆
StringGarble().str_grable(config)
# 四大组件类名混淆
ActivityGarble().activity_garble(config)
# 包路径混淆
PackageGarble().pkg_garble(config)
# Manifest混淆
ManifestGarble().manifest_garble(config)
# 插入乱码
JavaGarble().java_garble(config)
# 图片混淆
ImageGarble().img_garble(config)
# 编译release
Shell().build_release(config)
Shell().reset_project(config)
elif command == 2:
Function().new_appid(config)
elif command == 3:
Function().new_keystore(config)
elif command == 4:
Shell().push_project(config)
elif command == 5:
Shell().pull_base(config)
elif command == 6:
Shell().push_base(config)
elif command == 7:
Function().getFbSign(config)
elif command == 8:
Shell().push_with_tag(config)
elif command == 9:
Shell().reset_by_pkgname(config)
Function().move_resources(config)
elif command == 10:
Function().update_gateway(config)
elif command == 11:
Function().move_apk(config)
elif command == 12:
Function().cutover(config)
elif command == 13 or command == 133:
Function().print_checklist(config, command == 133)
print("Api混淆、包路径全混淆、四大组件混淆、manifest混淆、随机插入乱码、随机插入Activity、字符串加密、随机插入字符串、随机插入图片、数据插入布局,现有布局加入干扰")
print(" ")
elif command == 14:
Function().new_privacy(config)
elif command == 15:
Function().update_local_privacy(config)
elif command == 16:
ApiGarble().api_garble(config)
elif command == 17:
StringGarble().str_grable(config)
elif command == 18:
ActivityGarble().activity_garble(config)
elif command == 19:
PackageGarble().pkg_garble(config)
elif command == 20:
ManifestGarble().manifest_garble(config)
elif command == 21:
Shell().reset_project(config)
elif command == 22:
Shell().jiagu(config)
elif command == 23:
ImageGarble().img_garble(config)
elif command == 24:
JavaGarble().java_garble(config)
elif command == 25:
LayoutGarble().layout_garble(config)
elif command == 26:
SdkManager().sdk_manage(config)
elif command == 27:
Function().upate_keytore_sign(config)
elif command == 121:
Shell().install_app(config)
elif command == 122:
Function().crop_logo(config)
elif command == 123:
Function().find_logo(config)
# -*-coding:utf-8-*-
import os
class Shell:
# 编译 待开发
def build_release(self, config):
command = "%s\n%s\n%s\n%s\n%s\n" \
% (
"cd %s" % config['root'],
"rm -rf resGuardApks",
"gradlew clean",
"gradlew resguardAppProductGoogleplayRelease",
"gradlew clean"
)
os.system(command)
# commit&push project
def push_project(self, config):
command = "%s\n%s\n%s\n%s\n" \
% (
"cd %s" % config['root'],
"git add .",
"git commit -m \"%s\"" % (config['app_id'] +
" " + config['version_name']),
"git push origin %s" % config['git_branch']
)
os.system(command)
# commit&push lib_base
def push_base(self, config):
commit_msg = input("输入commit msg: ")
command = "%s\n%s\n%s\n%s\n" \
% (
"cd %s/%s" % (config['root'], "lib_base"),
"git add .",
"git commit -m \"%s\"" % commit_msg,
"git push origin master"
)
os.system(command)
# pull lib_base
def pull_base(self, config):
command = "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n" \
% (
"cd %s" % config['root'],
"git submodule update --remote",
"cd lib_base",
"git checkout master",
"git pull",
"cd ../lib_yitu || { echo \"lib_yitu not exist\"; exit 1; }",
"git checkout master",
"git pull"
)
os.system(command)
# push with tag
def push_with_tag(self, config):
self.push_project(config)
tagName = "t%s-%s" % (config['corp_id'], config['app_id'])
command = "%s\n%s\n%s\n%s\n%s\n" \
% (
"cd %s" % config['root'],
"git tag -d %s" % tagName,
"git push origin --delete tag %s" % tagName,
"git tag -a %s -m %s" % (tagName, tagName),
"git push origin %s" % tagName,
)
os.system(command)
# push with tag
def reset_by_pkgname(self, config):
pkgname = input("输入包名: ")
command = "%s\n%s" \
% (
"cd %s" % config['root'],
"git log --grep %s" % pkgname
)
os.system(command)
print(" ")
commit_id = input("输入commit id: ")
command = "%s\n%s" \
% (
"cd %s" % config['root'],
"git reset --hard %s" % commit_id
)
os.system(command)
print(" ")
# reset project
def reset_project(self, config):
command = "%s\n%s\n%s\n%s\n%s\n%s\n" \
% (
"cd %s" % config['root'],
"git checkout . && git clean -df",
"git reset --hard origin/%s" % config['git_branch'],
"cd lib_base || { echo \"lib_base not exist!\"; exit 1; }",
"git checkout . && git clean -df",
"git reset --hard origin/master"
)
os.system(command)
def jiagu(self, config):
# print("java -jar %s -importsign %s/app/%s %s %s %s"% (config['jiagu_jar'], config['root'], config['signing_certificate'], config['signging_certificatePassword'], config['signing_keyAlias'], config['signging_storePassword']))
# os.system("cd ../../app/../jks/\nls\n")
dirs = config['signing_certificate'].split("/")
jks_name = dirs[len(dirs)-1]
run_path = os.path.dirname(os.path.abspath(__file__))
jks_path = "%s/%s/%s"%(run_path, config['jks_path'], jks_name)
command = "%s\n%s\n%s\n%s\n"\
%(
"java -jar %s -login %s %s" % (config['jiagu_jar'], config['jiagu_account'], config["jiagu_pwd"]),
"java -jar %s -importsign %s %s %s %s"% (config['jiagu_jar'], jks_path, config['signging_certificatePassword'], config['signing_keyAlias'], config['signging_storePassword']),
"java -jar %s -config -update -nocert" % config['jiagu_jar'],
"java -jar %s -jiagu %s %s -autosign"% (config['jiagu_jar'], config['apk_path'], config['jiagu_output'])
)
os.system(command)
def install_app(self,config):
file_name = "%s_%s" % (
config['corp_id'], config['app_name'].replace(" ", "_"))
apk_local = "%s/resGuardApks/%s_release.apk" % (config['root'], file_name)
os.system("adb install %s"%apk_local)
# -*-coding:utf-8-*-
import glob, os
import string
import random
import re
class ActivityGarble:
__config = {}
used_names = []
activity_mapping = {}
#随机串
def __gen_rand_str(self):
rand_str = ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase, k=8))
while rand_str in self.used_names:
rand_str = ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase, k=8))
self.used_names.append(rand_str)
return rand_str
#替换文件内容
def __process_file_content(self, path, file_name):
# print("processing content: %s..."%path)
with open(path, "rt") as fin:
file_content = fin.read()
# replace the file content based on mangle settings
for (src, dst) in self.activity_mapping.items():
#避免命名重复,确保要替换的部分前后没有合法的命名字符,如果有则还原
file_content = file_content.replace(src, dst)
before = re.findall(r'[0-9a-zA-Z]'+dst,file_content)
if before is not None:
for name in before:
char = name.split(dst)[0]
file_content = file_content.replace(name, char + src)
after = re.findall(r''+ "%s[0-9a-zA-Z]"% dst,file_content)
if after is not None:
for name in after:
char = name.split(dst)[1]
file_content = file_content.replace(name, src + char)
ext = os.path.splitext(file_name)[1]
if ext == '.java':
comment = "// machine renamed: %s\n" % file_name
file_content = "%s%s" % (comment, file_content)
with open(path, "wt") as fout:
fout.write(file_content)
return
#查找所有待混淆类 并重命名
def __find_activities(self,path):
for root, dirs, files in os.walk(path):
directory = os.path.join(os.getcwd(), root)
for file in files:
is_activity = False
for file_name in self.__config['activities']:
if file.endswith(file_name):
is_activity = True
if is_activity:
name = os.path.splitext(file)[0]
if name not in self.activity_mapping.keys():
self.activity_mapping[name] = self.__gen_rand_str()
src = os.path.join(directory, file)
dst = os.path.join(directory, "%s.java" % self.activity_mapping[name])
os.rename(src, dst)
#遍历混淆文件
def __process_files(self,path):
for root, dirs, files in os.walk(path):
directory = os.path.join(os.getcwd(), root)
for file in files:
if file.endswith(".java") or file.endswith(".kt") or file.endswith(".xml"):
self.__process_file_content(os.path.join(directory, file),file)
#四大组件混淆
def activity_garble(self,config):
self.__config = config
#找到要混淆的java文件
print("find activity...")
for main_dir in config['lib_main']:
self.__find_activities("%s/%s"% (config['root'],main_dir))
#开始混淆
print("start garble ...")
for main_dir in config['lib_main']:
self.__process_files("%s/%s"% (config['root'],main_dir))
print("done")
# -*-coding:utf-8-*-
import glob, os
import string
import random
import base64
class ApiGarble:
#api混淆
def __rename_api(self,path,config):
with open("%s/script/api_mapping"%config['root'], "r", encoding="utf-8") as f:
lines = f.readlines()
for line in lines:
if "/sysdict/$1/$2" in line:
continue
#去除无用字符
line = line.replace(" "," ").replace("rewrite ^/","").replace("rewrite /","").replace("/(.+)","")\
.replace("/(.*)","").replace(" last;","").replace("\n","") \
.replace("/$1","").replace("/$2","").replace("/$3","").replace("/$4","").replace("/$5","")
if "$ /" in line:
line = line.replace("$ /","*-*")
else:
line = line.replace(" /","*-*")
api_map = line.split("*-*")
api_map[0].replace(" ","")
api_map[1].replace(" ","")
print(api_map[1]+ " -> " + api_map[0])
with open(path, "r", encoding="utf-8") as api_file:
api_lines = api_file.readlines()
#替换api
with open(path, "w", encoding="utf-8") as f_w:
for api_l in api_lines:
old_line = "//" + api_l.replace("\n","//rewrited\n")
if "loanapp/{loanAppId}/bank" in api_l:
api_l = api_l.replace("loanapp/{loanAppId}/bank","loanapp/bank/{loanAppId}")
if "*Keep*" not in api_l and (api_map[1]+"/{" in api_l or api_map[1]+"\"" in api_l) and ( "@GET" in api_l or "@PUT" in api_l or "@POST" in api_l):
api_l = api_l.replace(api_map[1], api_map[0])
api_l = old_line + api_l.replace("\n","//rewrited\n")
print(api_map[1]+ " -> " + api_map[0])
f_w.write(api_l)
print(path + " done\n")
return
def api_garble(self,config):
if not os.path.exists("%s/%s"% (config['root'], config['api_mapping'])):
print("api_mapping not found !")
return
for main_dir in config['lib_main']:
for root, dirs, files in os.walk("%s/%s"% (config['root'],main_dir)):
directory = os.path.join(os.getcwd(), root)
for file in files:
#要检索的文件名
if file.endswith("LoanApi.java") or file.endswith("UploadApi.java") or file.endswith("UserApi.java"):
# get the path of the java file
path = os.path.join(directory, file)
self.__rename_api(path,config)
import random
class ClassBuilder:
__used_names = []
__variables = []
__functions = []
__name = ""
def __gen_rand_str(self):
result = ""
while len(result) == 0 or result in self.__used_names:
random_str = ''.join(random.sample(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", random.randint(6, 10)))
result = "%s%d" % (random_str, random.randint(1, 100))
self.__used_names.append(result)
return result
# 生成变量
def __generate_variable(self):
var_scope = ["public", "private", "protected"]
var_types = ["String", "int", "double", "float"]
var_count = random.randint(3, 20)
for i in range(0, var_count):
code = "%s %s %s = " % (
var_scope[random.randint(0, 2)],
var_types[random.randint(0, 3)],
self.__gen_rand_str()
)
if " String " in code:
code += "\"%s\"" % self.__gen_rand_str()
else:
code += "%d" % random.randint(1, 1000)
code += ";"
self.__variables.append(code)
# 生成方法
def __generate_function(self, model_path):
func_scope = ["public", "private", "protected"]
return_type = ["String", "int", "double", "float"]
fun_content = ""
with open(model_path, "r", encoding="utf-8") as fin:
fun_content = fin.read()
re_type = return_type[random.randint(0, 3)]
fun_content = fun_content\
.replace("${func_scope}", func_scope[random.randint(0, 2)])\
.replace("${return_type}", re_type)\
.replace("${func_name}", self.__gen_rand_str())
# 方法参数
param_names = []
params_code = ""
for i in range(0, random.randint(1, 5)):
parans_name = self.__gen_rand_str()
code = "%s %s" % (
return_type[random.randint(0, 3)],
parans_name
)
params_code += code + ", "
param_names.append(parans_name)
params_code = ("%s*" % params_code).replace(", *", "")
fun_content = fun_content.replace("${params}", params_code)
# 随机引用全局变量
for var_code in self.__variables:
if random.randint(0, 2) % 2 == 0:
param_names.append(var_code.split(" ")[2])
return_value = ""
for name in param_names:
return_value += name + "+"
# 转string
return_value += "\"\""
if re_type in "int":
return_value = "(%s).length()" % return_value
elif re_type in "float":
return_value = "Float.valueOf((%s).length())" % return_value
elif re_type in "double":
return_value = "Double.valueOf((%s).length())" % return_value
return_value = "return %s;" % return_value
log_code = ""
for i in range(0, random.randint(0, 5)):
log_code += "Log.%s(\"%s\",\"%s\");\n" % (
''.join(random.sample("idew", random.randint(1, 1))),
self.__name,
''.join(random.sample("ABCDEFGHIJKLMNOPQRSTUVWXYZ", random.randint(5, 15)))
)
fun_content = fun_content.replace(
"${func_content}", log_code + return_value)
self.__functions.append(fun_content)
if len(self.__functions) < random.randint(3, 20):
self.__generate_function(model_path)
# 生成类
def __generate_class(self, model_path):
class_content = ""
with open(model_path, "r", encoding="utf-8") as fin:
class_content = fin.read()
variables = ""
for var_code in self.__variables:
variables += "%s\n" % var_code
functions = ""
for func_code in self.__functions:
functions += "%s\n\n" % func_code
return class_content.replace("${variable}", variables)\
.replace("${function}", functions)
def new_class(self,class_name,pkg_name):
self.__used_names = []
self.__variables = []
self.__functions = []
self.__name = class_name
self.__generate_variable()
self.__generate_function("tools/garble/model/function_model.java")
class_content = self.__generate_class("tools/garble/model/activity_model.java")
class_content = class_content.replace("${class_name}",class_name)\
.replace("${pkg_name}",pkg_name)
return class_content
from PIL import Image
from PIL import ImageDraw
import random
import os
import json
import sys
import time
class ImageGarble:
__colors = []
__used_names = []
# 随机串
def __gen_rand_str(self):
result = ""
while len(result) == 0 or result in self.__used_names:
result = ''.join(random.sample(
"abcdefghijklmnopqrstuvwxyz", random.randint(5, 15)))
self.__used_names.append(result)
return result
def __create_img(self, imgPath):
size = len(self.__colors)
image = Image.new('RGBA', (random.randint(1, 50), random.randint(
1, 50)), self.__colors[random.randint(0, size-1)])
image.save(imgPath, quality=10)
def img_garble(self, config):
with open("tools/garble/model/colors.json", "r", encoding="utf-8") as fin:
self.__colors = json.loads(fin.read())
count = 0
print("generating image ...")
for main_dir in config["lib_main"]:
for root, dirs, files in os.walk("%s/%s/res/" % (config['root'], main_dir)):
#改变现有图片MD5
for file in files:
if file.endswith(".png") or file.endswith(".webp"):
with open(os.path.join(root,file),"a") as f:
path = os.path.join(root,file)
with open(path,"a") as f:
f.write(str(time.time()+random.randint(1,10000)))
#创建随机图片
if len(files) > 0 and (".png" in str(files) or ".webp" in str(files)) :
print(root)
for i in range(0, random.randint(30, 50)):
#最多500张
if count > 500:
return
# img_path = "/Users/connor/Documents/apks/imgs/%s.png"%self.__gen_rand_str()
# self.__create_img(img_path)
self.__create_img("%s/%s.png"%(root,self.__gen_rand_str()))
count += 1
print("done")
print("已生成%d张图片"% count)
# -*-coding:utf-8-*-
import random
import re
import os
class JavaGarble:
__used_names = []
__functions = []
__logic_model = ""
__config = {}
def __gen_rand_str(self):
result = ""
while len(result) == 0 or result in self.__used_names:
result = ''.join(random.sample(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", random.randint(5, 12)))
self.__used_names.append(result)
return result
# 生成方法
def __generate_function(self, model_path):
func_scope = ["public", "private", "protected"]
return_type = ["String", "int", "double", "float"]
fun_content = ""
with open(model_path, "r", encoding="utf-8") as fin:
fun_content = fin.read()
re_type = return_type[random.randint(0, 3)]
fun_content = fun_content\
.replace("${func_scope}", func_scope[random.randint(0, 2)])\
.replace("${return_type}", re_type)\
.replace("${func_name}", self.__gen_rand_str())
# 方法参数
param_names = []
params_code = ""
for i in range(0, random.randint(1, 5)):
parans_name = self.__gen_rand_str()
code = "%s %s" % (
return_type[random.randint(0, 3)],
parans_name
)
params_code += code + ", "
param_names.append(parans_name)
params_code = ("%s*" % params_code).replace(", *", "")
fun_content = fun_content.replace("${params}", params_code)
# 随机引用全局变量
for var_code in self.__variables:
if random.randint(0, 2) % 2 == 0:
param_names.append(var_code.split(" ")[2])
return_value = ""
for name in param_names:
return_value += name + "+"
# 转string
return_value += "\"\""
if re_type in "int":
return_value = "(%s).length()" % return_value
elif re_type in "float":
return_value = "Float.valueOf((%s).length())" % return_value
elif re_type in "double":
return_value = "Double.valueOf((%s).length())" % return_value
return_value = "return %s;" % return_value
log_code = ""
for i in range(0, random.randint(0, 5)):
log_code += "android.util.Log.%s(\"%s\",\"%s\");\n" % (
''.join(random.sample("idew", random.randint(1, 1))),
''.join(random.sample(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ", random.randint(3, 10))),
''.join(random.sample(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ", random.randint(5, 15)))
)
fun_content = fun_content.replace(
"${func_content}", log_code + return_value)
self.__functions.append(fun_content)
if len(self.__functions) < random.randint(3, 10):
self.__generate_function(model_path)
# 插入代码
def __insert_code(self):
insert_code = ""
codes = self.__logic_model.split("@code\n")
# 选择一个变量
vars = codes[0].replace("\n", "").split("*")
index = random.randint(0, len(vars)-1)
# 选择一段逻辑代码
models = codes[2].split("@---sep---\n")
insert_code += models[random.randint(0, len(models)-1)]
# 选择一个判断条件
condition = codes[1].replace("\n", "").split("*")[index]
insert_code = insert_code.replace("${vars}", vars[index])\
.replace("${condition}", condition)
insert_code = insert_code.replace("${string1}", self.__gen_rand_str())\
.replace("${string2}", self.__gen_rand_str())\
.replace("${string3}", self.__gen_rand_str())\
.replace("${string4}", self.__gen_rand_str())\
.replace("${string5}", self.__gen_rand_str())\
.replace("${number1}", str(random.randint(1, 10000)))\
.replace("${number2}", str(random.randint(1, 10000)))\
.replace("${number3}", str(random.randint(1, 10000)))\
.replace("${number4}", str(random.randint(1, 10000)))\
.replace("${number5}", str(random.randint(1, 10000)))\
.replace("${name1}", self.__gen_rand_str())\
.replace("${name2}", self.__gen_rand_str())\
.replace("${name3}", self.__gen_rand_str())\
.replace("${name4}", self.__gen_rand_str())\
.replace("${name5}", self.__gen_rand_str())\
return insert_code
def __garble_java_file(self, file):
self.__used_names = []
self.__variables = []
self.__functions = []
with open(file, "r", encoding="utf-8") as fin:
lines = fin.readlines()
# 生成方法
self.__generate_function("tools/garble/model/function_model.java")
ignore = False
# 花括号
curly_braces = 0
# 忽略混淆的代码块
ignore_parts = {}
with open(file, "w+", encoding="utf-8") as fout:
for line in lines:
# interface 不混淆
if "interface" in line and "{\n" in line or ignore:
ignore = True
fout.write(line)
continue
if (line.startswith("class ") or " class " in line) and "{\n" in line and "//" not in line:
# 插入全局变量
for var in self.__variables:
line += "%s\n" % var
# 插入方法
for fun in self.__functions:
line += "%s\n" % fun
if curly_braces >= 1:
curly_braces += line.count("{")
curly_braces -= line.count("}")
# 定位1个缩进开头的类方法
if line.startswith(" ") and not line.startswith(" ") \
and ("){\n" in line or ") {\n" in line):
curly_braces = line.count("{")
curly_braces -= line.count("}")
for brace in ignore_parts.keys():
if curly_braces < brace:
ignore_parts[brace] = -10000
if "new" in line and "{\n" in line:
ignore_parts[curly_braces] = curly_braces
if curly_braces >= 1 and curly_braces not in ignore_parts.values():
if "return" in line or "throw" in line:
curly_braces = -10000
elif ";\n" in line and len(line.replace(" ","")) > 10 and "//" not in line:
#随机取余决定是否插入乱码
if random.randint(1,10) % random.randint(1,3) == 0:
line += self.__insert_code()
fout.write(line)
def java_garble(self, config):
self.__config = config
with open("tools/garble/model/logic_model.java", "r", encoding="utf-8") as fin:
self.__logic_model = fin.read().replace("\n\n", "\n").replace("\n\n", "\n")
print("ccode inserting ...")
for main_dir in config['lib_main']:
for root, dirs, files in os.walk("%s/%s" % (config["root"], main_dir)):
for file in files:
if file.endswith(".java") and file not in config['ignore_files']:
self.__garble_java_file(os.path.join(root, file))
print("done")
# -*-coding:utf-8-*-
import random
import re
import os
import json
class LayoutGarble:
__used_names = []
__layout_model = []
__colors = []
__config = []
def __gen_rand_str(self):
result = ""
while len(result) == 0 or result in self.__used_names:
result = ''.join(random.sample(
"abcdefghijklmnopqrstuvwxyz", random.randint(5, 12)))
self.__used_names.append(result)
return result
#随机取数组中一个item
def __rand_item(self, values):
return values[random.randint(0, len(values)-1)]
#填充属性值
def __set_values(self, attrs):
gravity = ['center_vertical', 'center_horizontal',
'left', 'right', 'bottom', 'top']
visibility = ['visible', 'invisible', 'gone']
boolean = ['true', 'false']
size = ['wrap_content', 'match_parent', '${number}dp']
orientation = ['horizontal', 'vertical']
scale_type = ['fitCenter', 'centerCrop', 'center',
'fitXY', 'centerInside', 'fitEnd', 'fitStart', 'matrix']
return attrs.replace("${id}", self.__gen_rand_str())\
.replace("${string}", self.__gen_rand_str())\
.replace("${color}", self.__rand_item(self.__colors))\
.replace("${gravity}", self.__rand_item(gravity))\
.replace("${visibility}", self.__rand_item(visibility))\
.replace("${boolean}", self.__rand_item(boolean))\
.replace("${number}", "%d"%random.randint(0, 500))\
.replace("${size}", self.__rand_item(size).replace("${number}", "%d"%random.randint(0, 500)))\
.replace("${orientation}", self.__rand_item(orientation))\
.replace("${scaleType}", self.__rand_item(scale_type))
#创建随机属性
def __create_attributes(self):
attrs = self.__layout_model[0].replace("\n","").split("*")
result = ""
length = int(len(attrs) / 2)
for i in range(0,random.randint(1, length)):
item = attrs[random.randint(0, len(attrs)-1)]
result += "%s\n" % self.__set_values(item)
attrs.remove(item)
return ("%s$"%result).replace("\n$","")
#创建随机数量的View
def __create_views(self,max):
view_model = self.__layout_model[2].split("@---sep---")
views = ""
for i in range(0,random.randint(1,max)):
view = self.__rand_item(view_model)
views += self.__set_values(view).replace("${attributes}", self.__create_attributes())
return views
#生成一个layout文件
def __create_layout(self, path):
layouts = self.__layout_model[1].split("@---sep---")
root_layout = self.__rand_item(layouts)
root_layout = root_layout.replace(
"${attributes}", "%s\n${attributes}" % "xmlns:android=\"http://schemas.android.com/apk/res/android\"")
root_layout = self.__set_values(root_layout).replace("${attributes}", self.__create_attributes())
content = ""
for i in range(0,random.randint(1,5)):
if random.randint(0,10) % random.randint(2,3) == 0:
layout = self.__rand_item(layouts).replace("${attributes}", self.__create_attributes())
layout = self.__set_values(layout).replace("${childs}",self.__create_views(4))
content += layout
else:
content += self.__create_views(4)
root_layout = root_layout.replace("${childs}",content)
with open(path,"w+",encoding='utf-8') as fout:
fout.write(root_layout)
#混淆已存在的layout
def __rewrite_layout(self,path):
with open(path,"r",encoding='utf-8') as fin:
lines = fin.readlines()
with open(path,"w+",encoding='utf-8') as fin:
ignores = []
for line in lines:
view_name = line.replace("<","").replace("/","").replace(">","").replace("\n","")
#自定义layout忽略
if "<" in line and "." in line and "/" not in line:
items = view_name.split(".")
if items[len(items)-1] in self.__config['ignore_layout']:
ignores.append(view_name)
if "/" in line and view_name in ignores:
ignores.remove(view_name)
if len(ignores) == 0 and "<!--" not in line:
if "</LinearLayout>" in line or "</RelativeLayout>" in line or "</FrameLayout>" in line or "<TextView" in line \
or "<ImageView" in line or "<EditText" in line or "<Button" in line or "<ImageButton" in line or "<CheckBox" in line:
if random.randint(0,10) % random.randint(2,3) == 0:
view = self.__create_views(1).replace("/>","\n%s/>"%"android:visibility=\"gone\"")
line = "%s\n%s"%(view,line)
fin.write(line)
#开始layout混淆
def layout_garble(self, config):
self.__config = config
with open("tools/garble/model/layout_model.xml", "r", encoding="utf-8") as fin:
self.__layout_model = fin.read().split("@code\n")
with open("tools/garble/model/colors.json", "r", encoding="utf-8") as fin:
self.__colors = json.loads(fin.read())
for main_dir in config['lib_main']:
for root, dirs, files in os.walk("%s/%s" % (config["root"], "%s/res/layout"%main_dir)):
print("layout generating ...")
for i in range(30,100):
self.__create_layout(os.path.join(root, "%s.xml" % self.__gen_rand_str()))
print("layout rewriting ...")
for file in files:
self.__rewrite_layout(os.path.join(root, file))
print("done")
import random
import os
from tools.garble.class_builder import ClassBuilder
class ManifestGarble:
__used_names = []
def __gen_rand_str(self):
result = ""
while len(result) == 0 or result in self.__used_names:
random_str = ''.join(random.sample(
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", random.randint(6, 10)))
result = "%s%d" % (random_str, random.randint(101, 200))
self.__used_names.append(result)
return result
#在包中随机创建Activity
def __create_activities(self,path):
activities = []
for root, dirs, files in os.walk(path):
rand_bool = random.randint(1,10) % random.randint(1,2) == 0
if rand_bool and len(files) > 0 and (files[0].endswith(".java") or files[0].endswith(".kt")):
for i in range(0,random.randint(3,10)):
act_name = self.__gen_rand_str()
act_path = "%s/%s.java"%(root, act_name)
pkg_name = ""
if "main/java/" in root:
pkg_name = root.split("main/java/")[1].replace("/",".")
elif "main/kotlin/" in root:
pkg_name = root.split("main/kotlin/")[1].replace("/",".")
act_content = ClassBuilder().new_class(act_name,pkg_name)
with open(act_path, "w+", encoding="utf-8") as fout:
fout.write(act_content)
activities.append("%s.%s"%(pkg_name,act_name))
return activities
def __insert_to_manifest(self,path,activities):
file_content = ""
with open(path,"r",encoding="utf-8") as fin:
file_content = fin.read()
for activity in activities:
code = "<activity android:name=\"%s\" />"%activity
file_content = file_content.replace("</application>","%s\n</application>"%code)
with open(path,"w",encoding="utf-8") as fout:
fout.write(file_content)
def manifest_garble(self, config):
for main_dir in config['lib_main']:
print("activity generating ...")
activities = self.__create_activities("%s/%s"%(config["root"], main_dir))
print("inster activity to manifest ...")
self.__insert_to_manifest("%s/%s/AndroidManifest.xml"% (config["root"], main_dir), activities)
print("done")
package ${pkg_name};
import android.app.Activity;
import android.util.Log;
public class ${class_name} extends Activity {
${variable}
${function}
}
\ No newline at end of file
[
"#FFFAFA",
"#BBFFFF",
"#F8F8FF",
"#AEEEEE",
"#F5F5F5",
"#96CDCD",
"#DCDCDC",
"#668B8B",
"#FFFAF0",
"#98F5FF",
"#FDF5E6",
"#8EE5EE",
"#FAF0E6",
"#7AC5CD",
"#FAEBD7",
"#53868B",
"#FFEFD5",
"#00F5FF",
"#FFEBCD",
"#00E5EE",
"#FFE4C4",
"#00C5CD",
"#FFDAB9",
"#00868B",
"#FFDEAD",
"#00FFFF",
"#FFE4B5",
"#00EEEE",
"#FFF8DC",
"#00CDCD",
"#FFFFF0",
"#008B8B",
"#FFFACD",
"#97FFFF",
"#FFF5EE",
"#8DEEEE",
"#F0FFF0",
"#79CDCD",
"#F5FFFA",
"#528B8B",
"#F0FFFF",
"#7FFFD4",
"#F0F8FF",
"#76EEC6",
"#E6E6FA",
"#66CDAA",
"#FFF0F5",
"#458B74",
"#FFE4E1",
"#C1FFC1",
"#FFFFFF",
"#B4EEB4",
"#000000",
"#9BCD9B",
"#2F4F4F",
"#698B69",
"#696969",
"#54FF9F",
"#708090",
"#4EEE94",
"#778899",
"#43CD80",
"#BEBEBE",
"#2E8B57",
"#D3D3D3",
"#9AFF9A",
"#191970",
"#90EE90",
"#000080",
"#7CCD7C",
"#6495ED",
"#548B54",
"#483D8B",
"#00FF7F",
"#6A5ACD",
"#00EE76",
"#7B68EE",
"#00CD66",
"#8470FF",
"#008B45",
"#0000CD",
"#00FF00",
"#4169E1",
"#00EE00",
"#0000FF",
"#00CD00",
"#1E90FF",
"#008B00",
"#00BFFF",
"#7FFF00",
"#87CEEB",
"#76EE00",
"#87CEFA",
"#66CD00",
"#4682B4",
"#458B00",
"#B0C4DE",
"#C0FF3E",
"#ADD8E6",
"#B3EE3A",
"#B0E0E6",
"#9ACD32",
"#AFEEEE",
"#698B22",
"#00CED1",
"#CAFF70",
"#48D1CC",
"#BCEE68",
"#40E0D0",
"#A2CD5A",
"#00FFFF",
"#6E8B3D",
"#E0FFFF",
"#FFF68F",
"#5F9EA0",
"#EEE685",
"#66CDAA",
"#CDC673",
"#7FFFD4",
"#8B864E",
"#006400",
"#FFEC8B",
"#556B2F",
"#EEDC82",
"#8FBC8F",
"#CDBE70",
"#2E8B57",
"#8B814C",
"#3CB371",
"#FFFFE0",
"#20B2AA",
"#EEEED1",
"#98FB98",
"#CDCDB4",
"#00FF7F",
"#8B8B7A",
"#7CFC00",
"#FFFF00",
"#00FF00",
"#EEEE00",
"#7FFF00",
"#CDCD00",
"#00FA9A",
"#8B8B00",
"#ADFF2F",
"#FFD700",
"#32CD32",
"#EEC900",
"#9ACD32",
"#CDAD00",
"#228B22",
"#8B7500",
"#6B8E23",
"#FFC125",
"#BDB76B",
"#EEB422",
"#EEE8AA",
"#CD9B1D",
"#FAFAD2",
"#8B6914",
"#FFFFE0",
"#FFB90F",
"#FFFF00",
"#EEAD0E",
"#FFD700",
"#CD950C",
"#EEDD82",
"#8B658B",
"#DAA520",
"#FFC1C1",
"#B8860B",
"#EEB4B4",
"#BC8F8F",
"#CD9B9B",
"#CD5C5C",
"#8B6969",
"#8B4513",
"#FF6A6A",
"#A0522D",
"#EE6363",
"#CD853F",
"#CD5555",
"#DEB887",
"#8B3A3A",
"#F5F5DC",
"#FF8247",
"#F5DEB3",
"#EE7942",
"#F4A460",
"#CD6839",
"#D2B48C",
"#8B4726",
"#D2691E",
"#FFD39B",
"#B22222",
"#EEC591",
"#A52A2A",
"#CDAA7D",
"#E9967A",
"#8B7355",
"#FA8072",
"#FFE7BA",
"#FFA07A",
"#EED8AE",
"#FFA500",
"#CDBA96",
"#FF8C00",
"#8B7E66",
"#FF7F50",
"#FFA54F",
"#F08080",
"#EE9A49",
"#FF6347",
"#CD853F",
"#FF4500",
"#8B5A2B",
"#FF0000",
"#FF7F24",
"#FF69B4",
"#EE7621",
"#FF1493",
"#CD661D",
"#FFC0CB",
"#8B4513",
"#FFB6C1",
"#FF3030",
"#DB7093",
"#EE2C2C",
"#B03060",
"#CD2626",
"#C71585",
"#8B1A1A",
"#D02090",
"#FF4040",
"#FF00FF",
"#EE3B3B",
"#EE82EE",
"#CD3333",
"#DDA0DD",
"#8B2323",
"#DA70D6",
"#FF8C69",
"#BA55D3",
"#EE8262",
"#9932CC",
"#CD7054",
"#9400D3",
"#8B4C39",
"#8A2BE2",
"#FFA07A",
"#A020F0",
"#EE9572",
"#9370DB",
"#CD8162",
"#D8BFD8",
"#8B5742",
"#FFFAFA",
"#FFA500",
"#EEE9E9",
"#EE9A00",
"#CDC9C9",
"#CD8500",
"#8B8989",
"#8B5A00",
"#FFF5EE",
"#FF7F00",
"#EEE5DE",
"#EE7600",
"#CDC5BF",
"#CD6600",
"#8B8682",
"#8B4500",
"#FFEFDB",
"#FF7256",
"#EEDFCC",
"#EE6A50",
"#CDC0B0",
"#CD5B45",
"#8B8378",
"#8B3E2F",
"#FFE4C4",
"#FF6347",
"#EED5B7",
"#EE5C42",
"#CDB79E",
"#CD4F39",
"#8B7D6B",
"#8B3626",
"#FFDAB9",
"#FF4500",
"#EECBAD",
"#EE4000",
"#CDAF95",
"#CD3700",
"#8B7765",
"#8B2500",
"#FFDEAD",
"#FF0000",
"#EECFA1",
"#EE0000",
"#CDB38B",
"#CD0000",
"#8B795E",
"#8B0000",
"#FFFACD",
"#FF1493",
"#EEE9BF",
"#EE1289",
"#CDC9A5",
"#CD1076",
"#8B8970",
"#8B0A50",
"#FFF8DC",
"#FF6EB4",
"#EEE8CD",
"#EE6AA7",
"#CDC8B1",
"#CD6090",
"#8B8878",
"#8B3A62",
"#FFFFF0",
"#FFB5C5",
"#EEEEE0",
"#EEA9B8",
"#CDCDC1",
"#CD919E",
"#8B8B83",
"#8B636C",
"#F0FFF0",
"#FFAEB9",
"#E0EEE0",
"#EEA2AD",
"#C1CDC1",
"#CD8C95",
"#838B83",
"#8B5F65",
"#FFF0F5",
"#FF82AB",
"#EEE0E5",
"#EE799F",
"#CDC1C5",
"#CD6889",
"#8B8386",
"#8B475D",
"#FFE4E1",
"#FF34B3",
"#EED5D2",
"#EE30A7",
"#CDB7B5",
"#CD2990",
"#8B7D7B",
"#8B1C62",
"#F0FFFF",
"#FF3E96",
"#E0EEEE",
"#EE3A8C",
"#C1CDCD",
"#CD3278",
"#838B8B",
"#8B2252",
"#836FFF",
"#FF00FF",
"#7A67EE",
"#EE00EE",
"#6959CD",
"#CD00CD",
"#473C8B",
"#8B008B",
"#4876FF",
"#FF83FA",
"#436EEE",
"#EE7AE9",
"#3A5FCD",
"#CD69C9",
"#27408B",
"#8B4789",
"#0000FF",
"#FFBBFF",
"#0000EE",
"#EEAEEE",
"#0000CD",
"#CD96CD",
"#00008B",
"#8B668B",
"#1E90FF",
"#E066FF",
"#1C86EE",
"#D15FEE",
"#1874CD",
"#B452CD",
"#104E8B",
"#7A378B",
"#63B8FF",
"#BF3EFF",
"#5CACEE",
"#B23AEE",
"#4F94CD",
"#9A32CD",
"#36648B",
"#68228B",
"#00BFFF",
"#9B30FF",
"#00B2EE",
"#912CEE",
"#009ACD",
"#7D26CD",
"#00688B",
"#551A8B",
"#87CEFF",
"#AB82FF",
"#7EC0EE",
"#9F79EE",
"#6CA6CD",
"#8968CD",
"#4A708B",
"#5D478B",
"#B0E2FF",
"#FFE1FF",
"#A4D3EE",
"#EED2EE",
"#8DB6CD",
"#CDB5CD",
"#607B8B",
"#8B7B8B",
"#C6E2FF",
"#1C1C1C",
"#B9D3EE",
"#363636",
"#9FB6CD",
"#4F4F4F",
"#6C7B8B",
"#696969",
"#CAE1FF",
"#828282",
"#BCD2EE",
"#9C9C9C",
"#A2B5CD",
"#B5B5B5",
"#6E7B8B",
"#CFCFCF",
"#BFEFFF",
"#E8E8E8",
"#B2DFEE",
"#A9A9A9",
"#9AC0CD",
"#00008B",
"#68838B",
"#008B8B",
"#E0FFFF",
"#8B008B",
"#D1EEEE",
"#8B0000",
"#B4CDCD",
"#7A8B8B",
"#90EE90"
]
\ No newline at end of file
${func_scope} ${return_type} ${func_name}(${params}){
${func_content}
}
\ No newline at end of file
android:id="@+id/${id}"*
android:background="${color}"*
android:layout_gravity="${gravity}"*
android:longClickable="${boolean}"*
android:clickable="${boolean}"*
android:layout_margin="${number}dp"*
android:layout_marginTop="${number}dp"*
android:layout_marginBottom="${number}dp"*
android:layout_marginRight="${number}dp"*
android:layout_marginLeft="${number}dp"*
android:padding="${number}dp"*
android:paddingLeft="${number}dp"*
android:paddingBottom="${number}dp"*
android:paddingRight="${number}dp"*
android:paddingTop="${number}dp"*
android:alpha="${number}"*
android:elevation="${number}dp"
@code
<LinearLayout
${attributes}
android:layout_width="${size}"
android:layout_height="${size}"
android:orientation="${orientation}">
${childs}
</LinearLayout>
@---sep---
<RelativeLayout
${attributes}
android:layout_width="${size}"
android:layout_height="${size}">
${childs}
</RelativeLayout>
@---sep---
<FrameLayout
${attributes}
android:layout_width="${size}"
android:layout_height="${size}">
${childs}
</FrameLayout>
@code
<TextView
${attributes}
android:layout_width="${size}"
android:layout_height="${size}"
android:textSize="${number}sp"
android:textColor="${color}"
android:text="${string}"/>
@---sep---
<ImageView
${attributes}
android:layout_width="${size}"
android:layout_height="${size}"
android:scaleType="${scaleType}"/>
@---sep---
<EditText
${attributes}
android:layout_width="${size}"
android:layout_height="${size}"
android:hint="${string}"/>
@---sep---
<Button
${attributes}
android:layout_width="${size}"
android:layout_height="${size}"
android:text="${string}"/>
@---sep---
<ImageButton
${attributes}
android:layout_width="${size}"
android:layout_height="${size}"
android:scaleType="${scaleType}" />
@---sep---
<CheckBox
${attributes}
android:layout_width="match_parent"
android:layout_height="match_parent"
android:checked="${boolean}"/>
\ No newline at end of file
String ${name1} = "${string1}";*
int ${name1} = ${number1};*
float ${name1} = ${number1};*
double ${name1} = ${number1};*
long ${name1} = ${number1};
@code
${name1}.contains("${string1}${string1}")*
${name1} > ${number1}*
${name1} < ${number1}*
${name1} == ${number1} + ${number1}*
${name1} <= ${number1} - ${number1}
@code
android.util.Log.d("${name1}","${name2}");
@---sep---
android.util.Log.e("${name1}","${name2}");
@---sep---
android.util.Log.i("${name1}","${name2}");
@---sep---
android.util.Log.v("${name1}","${name2}");
@---sep---
${vars}
while(${condition}){
System.out.println(${name1} + "${string2}" + "${string3}" + "${string4}" + "${string5}");
}
@---sep---
${vars}
for(int ${name2} = 0; ${condition}; ${name2}++ ){
String ${name3} = ${name2} + ${name1} + "${string4}";
System.out.println(${name3} + "${string2}" + "${string3}" );
}
@---sep---
${vars}
if(${condition}){
System.out.println(${name1} + "${string2}" + "${string3}" + "${string4}" );
}
@---sep---
${vars}
boolean ${name2} = ${condition};
if(${name2}){
System.out.println(${name1} + "${string2}");
}
@---sep---
String ${name1} = "${string1}";
System.out.println(${name1}+"${string2}");
@---sep---
float ${name1} = ${number1};
while((int)${name1} < (${name1} - 1)){
System.out.println("${string1}");
}
@---sep---
if(android.text.TextUtils.isEmpty(android.os.Build.BOARD)){
System.out.println("${string1}");
}
@---sep---
if(android.os.Build.DEVICE.equals("${string1}")){
System.out.println("${string2}");
}
\ No newline at end of file
# -*-coding:utf-8-*-
import glob
import os
import string
import random
class PackageGarble:
used_names = []
pkg_mapping = {}
# 随机串(全小写加下划线,避免和activity混淆重复)
def __gen_rand_str(self):
result = ""
while len(result) == 0 or result in self.used_names:
random_str1 = ''.join(random.sample(
"abcdefghijklmnopqrstuvwxyz", random.randint(3, 6)))
random_str2 = ''.join(random.sample(
"abcdefghijklmnopqrstuvwxyz", random.randint(3, 6)))
result = "%s_%s"%(random_str1,random_str2)
self.used_names.append(result)
return result
# 替换文件内容
def __process_file_content(self, path, file_name):
# print("processing content: %s..."%path)
with open(path, "rt") as fin:
file_content = fin.read()
# 必须先替换长路径
keys = sorted(self.pkg_mapping.keys(),
key=lambda i: len(i.split(".")), reverse=True)
for pkg in keys:
file_content = file_content.replace(pkg, self.pkg_mapping[pkg])
ext = os.path.splitext(file_name)[1]
with open(path, "wt") as fout:
fout.write(file_content)
return
# 搜集混淆字典
def __find_pkgs(self, path):
for root, dirs, files in os.walk(path):
if len(dirs) == 0 and ("main/java" in root or "main/kotlin" in root):
mp_path = root.split("main/java/")[1].replace("/", ".")
if "main/kotlin" in root:
mp_path = root.split("main/kotlin/")[1].replace("/", ".")
if mp_path not in self.pkg_mapping.keys():
random_str = ""
# 按长度排序
pkg_path = mp_path
keys = sorted(self.pkg_mapping.keys(),
key=lambda i: len(i), reverse=True)
for key in keys:
if pkg_path.startswith(key):
random_str += self.pkg_mapping[key]
pkg_path = pkg_path.replace(key, "")
# 没混淆过的包名补全混淆
for pkgname in pkg_path.split("."):
if len(pkgname) > 0:
if len(random_str) > 0:
random_str += "."
random_str += self.__gen_rand_str()
size = len(mp_path.split("."))
while size > 0:
if mp_path not in self.pkg_mapping.keys():
self.pkg_mapping[mp_path] = random_str
#添加一个结尾标识,避免有路径中间有重复的包名被替换
mp_path += "**"
mp_path = mp_path.replace(
".%s" % mp_path.split(".")[size-1], "")
random_str = random_str.replace(
".%s" % random_str.split(".")[size-1], "")
size -= 1
#重命名所有包路径
def __rename_pkg(self,path):
mapping = {}
for root, dirs, files in os.walk(path):
if "main/java" in root or "main/kotlin" in root:
root += "/"
mp_path = root.split("main/java/")[1].replace("/", ".")
if "main/kotlin" in root:
mp_path = root.split("main/kotlin/")[1].replace("/", ".")
for dir in dirs:
pkg_path = "%s%s"%(mp_path,dir)
for (key,value) in self.pkg_mapping.items():
if key.startswith(pkg_path):
index = len(pkg_path.split(".")) - 1
dir_name = value.split(".")[index]
old_name = os.path.join(os.path.join(os.getcwd(), root), dir)
new_name = os.path.join(os.path.join(os.getcwd(), root),dir_name )
mapping[old_name] = new_name
print ("rename %s -> %s"%(dir,dir_name))
break
keys = sorted(mapping.keys(),
key=lambda i: len(i.split("/")), reverse=True)
for key in keys:
os.rename(key, mapping[key])
def __process_files(self, path):
if os.path.isfile(path):
dirs = path.split("/")
file_name = dirs[len(dirs)-1]
self.__process_file_content(path, file_name)
else:
for root, dirs, files in os.walk(path):
directory = os.path.join(os.getcwd(), root)
for file in files:
if file.endswith(".java") or file.endswith(".kt") or file.endswith(".xml"):
self.__process_file_content(
os.path.join(directory, file), file)
#包路径混淆
def pkg_garble(self, config):
print("find pkgs...")
#生成混淆字典
for main_dir in config['lib_main']:
self.__find_pkgs("%s/%s" % (config['root'], main_dir))
# keys = sorted(self.pkg_mapping.keys(),
# key=lambda i: len(i.split(".")), reverse=True)
# for key in keys:
# print(key+" -> " + self.pkg_mapping[key])
#重命名路径
for main_dir in config['lib_main']:
self.__rename_pkg("%s/%s" % (config['root'], main_dir))
for (key,value) in self.pkg_mapping.items():
path_level = len(key.split("."))
#com. cn. 开头的二级包名不混淆,避免干扰到三方SDK
if path_level <= 2 and (key.startswith("com.") or key.startswith("cn.")):
self.pkg_mapping[key] = key
#单个一级包名,干扰太多,不混淆
elif path_level <= 1:
self.pkg_mapping[key] = key
#全局替换
for proguard in config['proguard']:
self.__process_files("%s/%s" % (config['root'],proguard))
for main_dir in config['lib_main']:
self.__process_files("%s/%s" % (config['root'], main_dir))
print("done")
if __name__ == "__main__":
#project 根目录
PackageGarble().pkg_garble({})
\ No newline at end of file
# -*-coding:utf-8-*-
import glob, os
import string
import random
import base64
class StringGarble:
__used_names = []
# 随机串(全小写加下划线,避免和activity混淆重复)
def __gen_rand_str(self):
result = ""
while len(result) == 0 or result in self.__used_names:
result = ''.join(random.sample(
"abcdefghijklmnopqrstuvwxyz", random.randint(5, 15)))
self.__used_names.append(result)
return result
#字符串混淆
def __string_garble(self,path):
with open(path, "r") as f:
lines = f.readlines()
with open(path, "w") as f_w:
for line in lines:
if "<string" in line and "</string>\n" in line and "<!" not in line:
if "*keep*" not in line:
line = line.replace("</string>\n", "")
str_name = line.split(">")[0] + ">"
str_value = line.split(">")[1]
number=""
for i in range(0,random.randint(2,15)):
number += str(random.randint(0,9))
randStr = str(number) + "#-#"
grable_str = str(base64.b64encode((randStr + str_value).encode("utf-8")), "utf-8")
line = str_name + randStr + grable_str + "</string>\n"
f_w.write(line)
return
#随机插入字符串
def __insert_strings(self,path):
with open(path, "r") as f:
fileContent = f.read()
strings_head = ""
strings_foot = ""
for i in range(0,random.randint(300,800)):
key = self.__gen_rand_str()
value = ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase, k=random.randint(5, 100)))
if i % random.randint(1,10) == 0:
strings_head += "<string name=\"%s\">%s</string>\n"% (key,value)
else:
strings_foot += "<string name=\"%s\">%s</string>\n"% (key,value)
with open(path, "w") as f_w:
fileContent = fileContent.replace("</resources>","%s\n</resources>"% strings_head)
fileContent = fileContent.replace("<resources>","<resources>\n%s"% strings_foot)
f_w.write(fileContent)
def str_grable(self,config):
for main_dir in config['lib_main']:
for root, dirs, files in os.walk("%s/%s/res"% (config['root'], main_dir)):
directory = os.path.join(os.getcwd(), root)
for file in files:
if file.endswith("strings.xml"):
# get the path of the java file
path = os.path.join(directory, file)
print("process %s"% path)
if config['string_encryption'] in "true":
self.__string_garble(path)
self.__insert_strings(path)
print("done")
\ No newline at end of file
#加固
root=${1}
jar_path=${2}
account='15902141504'
pwd='qwqw10010'
key_path="${root}/jks/"
java -jar ${jar_path} -login ${account} ${pwd}
java -jar ${jar_path} -importsign ../../${project_name}/app/${signing_certificate} ${signging_certificatePassword} ${signing_keyAlias} ${signging_storePassword}
#java -jar jiagu.jar -showsign
java -jar ${jar_path} -config -update -nocert
java -jar ${jar_path} -jiagu ../../${project_name}/resGuardApks/${project_name}_release.apk ../../${project_name}/resGuardApks -autosigns
cd ../../${project_name}
jiagu_apk=""
for file in resGuardApks/*; do
if [[ ${file} == *jiagu.apk ]]
then
jiagu_apk=${file}
fi
done
# V1 签名
jarsigner -verbose -digestalg SHA1 -sigalg MD5withRSA \
-keystore app/${signing_certificate} \
-storepass ${signging_storePassword} \
-keypass ${signging_certificatePassword} \
-signedjar resGuardApks/${project_name}_release_jg.apk ${jiagu_apk} \
${signing_keyAlias}
#copy到指定目录
now_time=$(date "+%Y-%m-%d %H_%M_%S")
cp "resGuardApks/${project_name}_release_jg.apk" "/Users/connor/Documents/apks/${project_name}_jg_${now_time}.apk"
# -*-coding:utf-8-*-
import os
import sys
import random
from PIL import Image, ImageDraw, ImageFont
class ScreenMaker:
text = [
"Mudah Diajukan\n Pengisian Data Tidak Rumit",
"Tidak bisa menyelesaikan masalah?\nKhawatir tentang masalah pendanaan?",
"Pinjaman Dana Santai\n Cepat Masuk dalam Rekening",
"Isi informasi dengan mudah dan\nkeluar dari hutan dengan cepat",
"Memberikan anda layanan \n pinjaman berkualitas",
"Membantu Anda mengatasi\n kesulitan keuangan",
"Aliran Dana Untuk Anda\n Uangmu Tercukupi Di Sini",
"Pinjaman Semakin Nyaman\n Kangan Ragu! Unduh APPnya",
"Ambil Keberuntungan Kamu\n Bersama Kami Duitmu Beres",
"Membantu Anda keluar dari masalah\n dan menyelesaikan kesulitan keuangan",
"Hadir Utk Area Indonesia\n Layanan Pelanggan Sapa Ramah"
]
def draw_bg(self, bg_path, logo_path, top_path, output):
img_bg = Image.open(bg_path)
img_logo = Image.open(logo_path)
img_top = Image.open(top_path)
text_h = random.randint(0, 1400)
logo_h = random.randint(0, 1400)
top_h = random.randint(0, 1400)
text_index = random.randint(0, len(self.text)-1)
while abs(logo_h - text_h) < 400 or abs(top_h - text_h) < 400:
logo_h = random.randint(0, 1400)
top_h = random.randint(0, 1400)
# 添加背景
new_img = Image.new(
'RGBA', (img_bg.size[0] * 2, img_bg.size[1]), (0, 0, 0, 0))
new_img.paste(img_bg, (0, 0))
new_img.paste(img_bg, (img_bg.size[0], 0))
img_logo = img_logo.resize((300, 300), Image.ANTIALIAS)
img_top = img_top.resize((700, 342), Image.ANTIALIAS)
# logo随机位置
new_img.paste(img_logo, (random.randint(0, 700), logo_h))
new_img.paste(img_top, (1080, top_h))
# 字体随机大小
font_size = random.randint(120, 180)
font = ImageFont.truetype('Arial.ttf', font_size)
# 添加字体
new_img = new_img.convert('RGBA')
img_text = Image.new('RGBA', new_img.size, (255, 255, 255, 0))
image_draw = ImageDraw.Draw(img_text)
image_draw.text((random.randint(0, 300), text_h),
self.text[text_index], font=font, fill="#FFFFFF")
bg_with_text = Image.alpha_composite(new_img, img_text)
# 裁切图片
screen1 = bg_with_text.crop((0, 0, img_bg.size[0], img_bg.size[1]))
screen2 = bg_with_text.crop(
(img_bg.size[0], 0, img_bg.size[0]*2, img_bg.size[1]))
screen1.save(output+"/screen1.png", "PNG")
screen2.save(output+"/screen2.png", "PNG")
#!/usr/bin/env python3
import json
import string
import random
import glob, os
import sys
class SdkManager:
def __disable_code(self, path, sdk):
# print("processing content: %s..." % path)
with open(path, "r", encoding="utf-8") as f:
lines = f.readlines()
with open(path, "w", encoding="utf-8") as f_w:
is_sdk_code = False
for line in lines:
if "//SDK-"+sdk+"-END" in line or "<!--SDK-"+sdk+"-END-->" in line:
is_sdk_code = False
java_mark ="//SDK-" + sdk + "-CODE ->";
xml_mark ="<!--SDK-" + sdk + "-CODE//";
if (path.endswith(".java") or path.endswith(".gradle")) and is_sdk_code and java_mark not in line:
line = java_mark + line
if path.endswith(".xml") and is_sdk_code and xml_mark not in line:
line = xml_mark + line.replace("\n","//-->\n")
if "//SDK-"+sdk+"-START" in line or "<!--SDK-"+sdk+"-START-->" in line:
is_sdk_code = True
f_w.write(line)
return
def __enable_code(self, path, sdk):
# print("processing content: %s..." % path)
code_mark = "//SDK-" + sdk + "-CODE ->"
xml_mark = "<!--SDK-" + sdk + "-CODE//"
with open(path, "r", encoding="utf-8") as f:
lines = f.readlines()
with open(path, "w", encoding="utf-8") as f_w:
for line in lines:
if code_mark in line:
line = line.replace(code_mark,"")
if xml_mark in line:
line = line.replace(xml_mark,"").replace("//-->","")
f_w.write(line)
return
def __process_files(self, path, enable, sdk_mark):
if not os.path.isdir(path):
if enable:
self.__enable_code(path, sdk_mark)
else:
self.__disable_code(path, sdk_mark)
else:
for root, dirs, files in os.walk(path):
directory = os.path.join(os.getcwd(), root)
for file in files:
if file.endswith(".java") or file.endswith("AndroidManifest.xml") or file.endswith(".gradle"):
# get the path of the java file
path = os.path.join(directory, file)
if enable:
self.__enable_code(path, sdk_mark)
else:
self.__disable_code(path, sdk_mark)
def start_process(self, config, enable, sdk_mark):
#混淆build.gradle
self.__process_files("%s/app/build.gradle"% config['root'], enable, sdk_mark)
self.__process_files("%s/lib_base/build.gradle"% config['root'], enable, sdk_mark)
#混淆代码
self.__process_files("%s/app/src/main"% config['root'], enable, sdk_mark)
self.__process_files("%s/lib_base/src/main"% config['root'], enable, sdk_mark)
print("done")
def sdk_manage(self, config):
print(" ")
print("1、启用SDK")
print("2、禁用SDK")
command = int(input("请输入指令编号:"))
print(" ")
print("占位的标记:ADVANCE、YITU、MOTION 等")
sdk = str(input("要操作的SDK:"))
if command == 1:
self.start_process(config, True, sdk)
else:
self.start_process(config, False, sdk)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment