Пример #1
0
    def old_mode_generate_subpackage(self,
                                     task: Task,
                                     ext,
                                     auto_test: AutoTestInfo = None) -> bool:
        channel_id = task.params_info.common_params.channel_id
        for package_id in task.params_info.common_params.package_chanle:
            start_time = int(time.time())  # 统计处理分包起始时间

            Flog.i("正在打第{0}/{1}个分包,分包ID={2}".format(self.__current_index + 1,
                                                    self.__package_count,
                                                    package_id))
            if task.bag_info.group_id == "5":
                if not invoke_script.game(task, ext):
                    self.__wx_err_msg = "打分包执行游戏脚本失败"
                    return False
            if not pack_core.handle_common_params(task, channel_id,
                                                  package_id):
                self.__wx_err_msg = "打分包执行handle_v3_common_params失败"
                return False
            if not self.__compile(task):
                self.__wx_err_msg = "打分包回编译失败"
                return False
            signed, new_apk = self.__sign(task, package_id)

            if not signed:
                self.__wx_err_msg = "打分包重签名失败"
                return False

            if not self.__upload_bag(task, new_apk, package_id, start_time,
                                     auto_test):
                return False
        return True
Пример #2
0
def del_system_label(label):
    # 开始删除字段
    filelist = ["colors", "dimens", "ids", "public", "strings", "styles"]

    for f in filelist:
        fpath = FPath.DECOMPILE_PATH + "/res/values/" + f + ".xml"
        if os.path.exists(fpath):
            tree = elementTree.parse(fpath)
            root = tree.getroot()
            for node in list(root):
                attrib_name = node.attrib.get('name')
                if attrib_name is None:
                    continue

                if attrib_name.lower().startswith(label):
                    root.remove(node)
                    Flog.i("remove debug res index name:" + attrib_name +
                           " from" + fpath)
            tree.write(fpath, "UTF-8")

    res_path = FPath.DECOMPILE_PATH + "/res"
    filelist = []
    fio.list_file(res_path, filelist, [])
    for f in filelist:
        if os.path.basename(f).lower().startswith(label):
            fio.del_file_folder(f)
            Flog.i("remove debug res file:" + f)
Пример #3
0
def handle_origin_res() -> bool:
    try:
        files = []
        fio.list_file(FPath.DECOMPILE_PATH + "/res", files)
        for file in files:
            if "authsdk_" in file and os.path.exists(file):
                os.remove(file)
            if "umcsdk_" in file and os.path.exists(file):
                os.remove(file)
            if "kkk_" in file and os.path.exists(file):
                os.remove(file)

        xml_list = ["colors", "dimens", "ids", "public", "strings", "styles"]
        for f in xml_list:
            xml_path = FPath.DECOMPILE_PATH + "/res/values/" + f + ".xml"

            if os.path.exists(xml_path):
                tree = elementTree.parse(xml_path)
                root = tree.getroot()
                for node in list(root):
                    attrib_name = node.attrib.get('name')
                    if attrib_name is None:
                        continue
                    if attrib_name.lower().startswith("authsdk_"):
                        root.remove(node)
                    if attrib_name.lower().startswith("kkk_"):
                        root.remove(node)
                tree.write(xml_path, "UTF-8")

        return True
    except Exception as e:
        Flog.i("handle_origin_res() error " + str(e))
    return False
Пример #4
0
def handle_v3_origin() -> bool:
    if handle_origin_assets() and handle_origin_res() and handle_smali():
        Flog.i("handle_v3_origin() success")
        return True
    else:
        Flog.i("handle_v3_origin() error")
        return False
Пример #5
0
def removeMinifestComponentByName(decompileDir, typeName, componentName):
    manifestFile = decompileDir + "/AndroidManifest.xml"
    ET.register_namespace('android', androidNS)
    key = '{' + androidNS + '}name'

    tree = ET.parse(manifestFile)
    root = tree.getroot()

    applicationNode = root.find('application')
    if applicationNode is None:
        return

    activityNodeLst = applicationNode.findall(typeName)
    if activityNodeLst is None:
        return

    for activityNode in activityNodeLst:

        name = activityNode.get(key)
        if name == componentName:
            applicationNode.remove(activityNode)
            break

    tree.write(manifestFile, 'UTF-8')
    Flog.i("remove " + componentName + " from AndroidManifest.xml")

    return componentName
Пример #6
0
 def post(url: str, raw: str, upload: bool = False, file_link: str = "") -> ResultInfo:
     """
     加密流程:
     1)当前时间戳+10位长度Digits(0-9)随机数进行32位小写的md5加密得到原始秘钥raw_key
     2)把原始秘钥raw_key正序和倒序拼接成64位长度字符串进行16位小写的md5加密得到AES秘钥aes_key
     3)使用AES秘钥aes_key对数据进行AES/CBC/PKCS5Padding加密得到数据密文p
     """
     Flog.i("请求参数 : " + raw)
     time_stamp = str(int(time.time()))
     raw_key = cipher.get_32low_md5(time_stamp + cipher.get_random_str())
     aes_key = cipher.get_16low_md5(raw_key + raw_key[::-1])
     # p = cipher.urlencode(cipher.AesCipher.encrypt(raw, aes_key))
     p = cipher.urlencode(cipher.AesCipher.encrypt(raw, aes_key))
     ts = raw_key
     enc_url = url + "&p=" + p + "&ts=" + ts
     Flog.i("logTag " + time_stamp + " : url = " + enc_url)
     try:
         if upload:
             Flog.i("post upload")
             with open(file_link, encoding="utf-8") as f:
                 result = requests.post(enc_url, files={"log_file": f})
         else:
             result = requests.post(enc_url, headers={"Connection": "close"}, verify=False, timeout=5)
         Flog.i("返回内容 : " + result.text)
         return ResultInfo(result.text)
     except Exception as e:
         info = {
             "status": -1,
             "msg": str(e),
             "result": {}
         }
         Flog.i("请求异常 : " + str(e))
         return ResultInfo(json.dumps(info))
Пример #7
0
def check_game_resource(task: Task) -> bool:
    Flog.i("检查游戏资源")
    try:
        icon_url = task.params_info.game_params.game_icon_url
        logo_url = task.params_info.game_params.game_logo_url
        splash_url = task.params_info.game_params.game_splash_url
        background_url = task.params_info.game_params.game_background_url
        loading_url = task.params_info.game_params.game_loading_url
        resource_url = task.params_info.game_params.game_resource_url

        if not is_empty(icon_url):
            icon = Download.download_file(icon_url, FPath.RESOURCE_PATH, 1)
        if not is_empty(logo_url):
            logo = Download.download_file(logo_url, FPath.RESOURCE_PATH, 2)
        if not is_empty(splash_url):
            splash = Download.download_file(splash_url, FPath.RESOURCE_PATH, 3)
        if not is_empty(background_url):
            background = Download.download_file(background_url,
                                                FPath.RESOURCE_PATH, 4)
        if not is_empty(background_url):
            loading = Download.download_file(loading_url, FPath.RESOURCE_PATH,
                                             5)
        if not is_empty(resource_url):
            resource = Download.download_file(resource_url,
                                              FPath.RESOURCE_PATH)
            if fio.unzip(FPath.RESOURCE_PATH + "/" + resource,
                         FPath.RESOURCE_PATH):
                os.remove(FPath.RESOURCE_PATH + "/" + resource)

        return True

    except Exception as e:
        Flog.i(str(e))
        return False
Пример #8
0
    def _replace(self, file_name, key: str, value: str):
        # tempfile默认模式是w+b,写入的是byte,需要改成w+ 才能写入字符串
        # 或者也可以不改这个模式,在写入时候转成byte,取出时再传string
        tfile = tempfile.TemporaryFile(mode="w+")
        from_regex = key + ".*=.*"
        if os.path.exists(file_name):
            r_open = open(file_name, 'r', encoding="utf-8")
            pattern = re.compile(r'' + from_regex)
            found = None
            for line in r_open:
                if pattern.search(line) and not line.strip().startswith('#'):
                    found = True
                    save_value = key + "=" + value
                    line = re.sub(from_regex, save_value, line)
                tfile.writelines(line)
            if not found and self.append_on_not_exists:
                kav = "\n" + key + "=" + str(value)
                tfile.writelines(kav)
            r_open.close()
            tfile.seek(0)
            content = tfile.read()

            if os.path.exists(file_name):
                fio.remove_files(file_name)

            w_open = open(file_name, 'w', encoding="utf-8")
            w_open.writelines(content)
            w_open.close()

            tfile.close()

        else:
            Flog.i("file %s not found" % file_name)
Пример #9
0
    def __upload_bag(self,
                     task: Task,
                     new_apk: str,
                     package_id: str,
                     start_time: int,
                     compile_time: int = 0,
                     auto_test: AutoTestInfo = None) -> bool:
        # 上传包
        bag_url = self.__upload(task, new_apk)
        if bag_url is None and bag_url == '':
            self.__wx_err_msg = "打分包上传包体失败"
            return False

        if os.path.exists(new_apk):
            # 分包大小
            self.__data["package_size"] = os.path.getsize(new_apk)
            # 删除新包
            os.remove(new_apk)

        # 上报打包状态
        self.__data["package_id"] = package_id
        self.__data["status_code"] = 1210
        self.__data["bag_url"] = bag_url
        if self.__current_index + 1 == 1:
            self.__data["ext"]["from_time"] = int(
                time.time()) - start_time + compile_time  # 分包处理时间
        else:
            self.__data["ext"]["from_time"] = int(
                time.time()) - start_time  # 分包处理时间
        self.__random_link_list.append(bag_url)
        self.__package_id_list.append(package_id)
        is_stop, msg = self.__report_status(self.__data)
        if not msg:
            # 上报打包状态接口正常
            # 是否中止执行
            if is_stop:
                Flog.i("中断任务")
                return True
            # 判断是否最后一个子包
            self.__current_index += 1
            if self.__current_index == self.__package_count:
                # 上报任务状态(成功)
                random_link = random.choice(self.__random_link_list)
                random_package_id = self.__package_id_list[
                    self.__random_link_list.index(random_link)]
                result, err_msg = self.report_task(task, 1210,
                                                   random_package_id,
                                                   random_link, auto_test)
                if err_msg:
                    self.__wx_err_msg = err_msg
                return result
            return True
        else:
            # 上报打包状态接口异常
            Flog.i("上报打包成功接口异常")
            self.__wx_err_msg = msg
            return False
Пример #10
0
 def send_msg_2_wx(url: str, data: dict) -> str:
     headers = {"Content-Type": "application/json; charset=UTF-8"}
     try:
         result = requests.post(url, json.dumps(data), headers=headers)
         Flog.i(result.text)
         return result.text
     except Exception as e:
         Flog.i("请求异常 : " + str(e))
         return str(e)
Пример #11
0
def insert_file_2_apk(apk_path: str, target_path: str, data: bytes) -> bool:
    try:
        with zipfile.ZipFile(apk_path, "a") as zf:
            with zf.open(target_path, "w") as f:
                f.write(data)
        return True
    except Exception as e:
        Flog.i(str(e))
        return False
Пример #12
0
def modifyRootApplicationExtends(decompileDir, applicationClassName):
    applicationSmali = find_root_application_smali(decompileDir)
    if applicationSmali is None:
        Flog.i("the applicationSmali get failed.")
        return

    Flog.i("modifyRootApplicationExtends: root application smali: " +
           applicationSmali)

    modifyApplicationExtends(applicationSmali, applicationClassName)
Пример #13
0
 def __decompile(task: Task):
     """
     反编译母包
     :param task:
     :return:
     """
     Flog.i("反编译母包")
     if android.decompile_apk(task):
         return True
     else:
         return False
Пример #14
0
def create_app() -> Flask:
    app = Flask(__name__)

    app.response_class = JSONResponse
    impl = ImplManager()
    Flog.init()

    task_cache.init_cache(app)
    task_scheduler.init_scheduler(app, impl)

    return app
Пример #15
0
def dex2smali(src_dir: str, dst_dir: str) -> bool:
    baksmali_tool = FPath.BAKSMALI_JAR
    if not os.path.exists(src_dir):
        Flog.i("classes.dex is can not found , where : " + src_dir)
        return False
    if not os.path.exists(dst_dir):
        os.makedirs(dst_dir)

    cmd = get_java_shell() + " -jar %s -o %s %s" % (baksmali_tool, dst_dir,
                                                    src_dir)
    return command.exec_command(cmd)
Пример #16
0
def parse_class(line):
    """
    parse class line
    :param line:
    :return:
    """
    if not line.startswith(".class"):
        Flog.i("line parse error. not startswith .class : " + line)
        return None

    blocks = line.split()
    return blocks[len(blocks) - 1]
Пример #17
0
def handle_origin() -> bool:
    """
    处理母包
    :return:
    """
    if is_v3_mode():
        Flog.i("v3版本母包")
        result = handle_v3_origin()
    else:
        Flog.i("v2版本母包")
        result = handle_v2_origin()
    return result
Пример #18
0
def parse_method_invoke(line):
    if not line.startswith("invoke-"):
        Flog.i("the line parse error in parse_method_invoke:" + line)

    blocks = line.split("->")
    method = blocks[len(blocks) - 1]

    pre_blocks = blocks[0].split(",")
    class_name = pre_blocks[len(pre_blocks) - 1]
    class_name = class_name.strip()

    return class_name, method
Пример #19
0
def parse_method_default(line):
    """
    parse default method
    :param line:
    :return:
    """
    if not line.startswith(".method"):
        Flog.i("the line parse error in parse_method_default:" + line)
        return None

    blocks = line.split()
    return blocks[len(blocks) - 1]
Пример #20
0
def handle_v2_origin() -> bool:
    if del_smali_code() and delete_so_file() and del_3k_res(
    ) and del_manifest_infos(FPath.DECOMPILE_PATH):
        del_system_label('$')
        del_system_label('ic_launcher_foreground')
        del_system_label('ic_launcher_background')
        fio.del_file_folder(FPath.DECOMPILE_PATH + "/res/mipmap-anydpi-v26")
        fio.del_file_folder(FPath.DECOMPILE_PATH + "/res/drawable-v24")
        Flog.i("handle_v2_origin() success")
        return True
    else:
        Flog.i("handle_v2_origin() error")
        return False
Пример #21
0
def check_keystore(task: Task) -> bool:
    Flog.i("检查签名文件资源")
    try:
        keystore_info = task.keystore_info
        file_name = Download.download_file(keystore_info.file_url,
                                           FPath.WORKSPACE_PATH)
        if file_name != keystore_info.keystore_name:
            os.rename(FPath.WORKSPACE_PATH + "/" + file_name,
                      FPath.WORKSPACE_PATH + "/" + keystore_info.keystore_name)
        return True
    except Exception as e:
        Flog.i(str(e))
    return False
Пример #22
0
def handle_v3_common_params(channel_id: str,
                            package_id: str,
                            new_mode: bool = False):
    if new_mode:
        fuse_prop_file = FPath.WORKSPACE_PATH + "/fuse_cfg.properties"
    else:
        fuse_prop_file = FPath.DECOMPILE_PATH + "/assets/fuse_cfg.properties"
    if not os.path.exists(fuse_prop_file):
        Flog.i("fuse_cfg.properties not exists")
        return False
    try:
        prop = fprop.parse(fuse_prop_file)
        # 写入融合渠道id
        if is_empty(channel_id):
            Flog.i("channel_id 不能为空")
            return False
        else:
            prop.put("3KWAN_Platform_ChanleId", channel_id)
        # 写入融合渠道id
        if is_empty(package_id):
            Flog.i("package_id 不能为空")
            return False
        else:
            prop.put("3KWAN_PackageID", package_id)
        prop.save()
        return True
    except Exception as e:
        Flog.i("handle_v3_common_params() error " + str(e))
        return False
Пример #23
0
def handle_smali() -> bool:
    try:
        if os.path.exists(FPath.DECOMPILE_PATH + "/smali/com/didi"):
            shutil.rmtree(FPath.DECOMPILE_PATH + "/smali/com/didi")
        if os.path.exists(FPath.DECOMPILE_PATH + "/smali/com/tencent"):
            shutil.rmtree(FPath.DECOMPILE_PATH + "/smali/com/tencent")
        if os.path.exists(FPath.DECOMPILE_PATH + "/smali/cn/impl"):
            shutil.rmtree(FPath.DECOMPILE_PATH + "/smali/cn/impl")
        if os.path.exists(FPath.DECOMPILE_PATH + "/smali/cn/kkk"):
            shutil.rmtree(FPath.DECOMPILE_PATH + "/smali/cn/kkk")
        return True
    except Exception as e:
        Flog.i("handle_smali() error " + str(e))
    return False
Пример #24
0
def del_3k_res() -> bool:
    """
    delete 3k res eg:kkk_
    :return:
    """
    try:
        res_path = FPath.DECOMPILE_PATH + "/res"
        if not os.path.exists(res_path):
            Flog.i("can't find this res path : " + res_path)
            return False

        res_files = []
        fio.list_file(res_path, res_files, [])
        if res_files is None or len(res_files) <= 0:
            return True

        for res in res_files:
            if "kkk_" in res:
                fio.del_file_folder(res)

        # 开始删除字段
        # decompile_dir = path_utils.get_full_path(decompile_dir)
        file_list = ["colors", "dimens", "ids", "public", "strings", "styles"]
        for f in file_list:
            fpath = FPath.DECOMPILE_PATH + "/res/values/" + f + ".xml"
            if os.path.exists(fpath):
                tree = elementTree.parse(fpath)
                root = tree.getroot()
                for node in list(root):
                    attrib_name = node.attrib.get("name")
                    if attrib_name is None:
                        continue

                    if attrib_name.lower().startswith(
                            "kkk_") or attrib_name.lower().startswith("tk_"):
                        root.remove(node)
                tree.write(fpath, "UTF-8")

        res_path = FPath.DECOMPILE_PATH + "/res"
        xml_list = []
        fio.list_file(res_path, xml_list, [])
        for xml in xml_list:
            if os.path.basename(xml).lower().startswith(
                    "kkk_") or os.path.basename(xml).lower().startswith("tk_"):
                fio.del_file_folder(xml)

        return True
    except Exception as e:
        Flog.i("del_3k_res() error " + str(e))
        return False
Пример #25
0
 def handle_result(result) -> dict:
     p = ""
     ts = ""
     if result:
         if "p" in result:
             p = result["p"]
         if "ts" in result:
             ts = result["ts"]
         aes_key = cipher.get_16low_md5(ts + ts[::-1])
         raw = cipher.urldecode(
             cipher.AesCipher.decrypt(cipher.urldecode(p), aes_key))
         result = json.loads(raw)
         Flog.i("解析数据 : " + dict_2_str(result))
         return result
Пример #26
0
def copyResource(task: Task, sdkDir):
    """
    Copy comsdk resources to the apk decompile dir
        Merge manifest.xml
        Merge all res xml if the xml already exists in target apk.
        copy all others resources
    :return:
    """
    # start to merge manifest.xml
    manifestFrom = sdkDir + "/SDKManifest.xml"
    manifestFromTemp = manifestFrom
    manifestTo = FPath.DECOMPILE_PATH + "/AndroidManifest.xml"

    if task.params_info.game_params.game_orientation == 1:  # 'portrait'
        manifestFrom = manifestFrom[:-4] + "_portrait.xml"
    else:
        manifestFrom = manifestFrom[:-4] + "_landscape.xml"

    if not os.path.exists(manifestFrom):
        manifestFrom = manifestFromTemp

    if os.path.exists(manifestFrom):
        # merge into xml
        bRet = mergeManifest(manifestTo, manifestFrom)
        if bRet:
            Flog.i("merge manifest file success.")
        else:
            Flog.i("merge manifest file failed.")
            return 1

    # copyRes
    copyFrom = sdkDir + "/res"
    copyTo = FPath.DECOMPILE_PATH + "/res"

    if os.path.exists(copyFrom):
        copyResToApk(copyFrom, copyTo)

    # copyAssets
    assetsFrom = sdkDir + "/assets"
    assetsTo = FPath.DECOMPILE_PATH + "/assets"
    if os.path.exists(assetsFrom):
        copyResToApk(assetsFrom, assetsTo)

    # copyLibs
    libFrom = sdkDir + "/libs"
    libTo = FPath.DECOMPILE_PATH + "/lib"
    if os.path.exists(libFrom):
        copyLibs(libFrom, libTo)
Пример #27
0
def get_smali_method_count(smaliFile, allMethods):
    """
    get smali methods count
    :param smaliFile:
    :param allMethods:
    :return:
    """
    if not os.path.exists(smaliFile):
        return 0

    f = open(smaliFile, encoding='UTF-8', errors='ignore')
    lines = f.readlines()
    f.close()

    if lines is None or len(lines) <= 0:
        return 0

    class_line = lines[0]
    class_line = class_line.strip()
    if not class_line.startswith(".class"):
        Flog.i(smaliFile + " not startswith .class")
        return 0
    class_name = parse_class(class_line)

    count = 0
    for line in lines:
        line = line.strip()

        method = None
        temp_class_name = class_name
        if line.startswith(".method"):
            method = parse_method_default(line)
        elif line.startswith("invoke-"):
            temp_class_name, method = parse_method_invoke(line)

        if method is None:
            continue

        if temp_class_name not in allMethods:
            allMethods[temp_class_name] = list()

        if method not in allMethods[temp_class_name]:
            count = count + 1
            allMethods[temp_class_name].append(method)
        else:
            pass

    return count
Пример #28
0
    def __download(download_name: str, file_link: str, save_path: str) -> str:
        print("down file_link:" + file_link)
        try:
            with DownloadHook(unit="B",
                              unit_scale=True,
                              unit_divisor=1024,
                              miniters=1,
                              desc=download_name) as hook:

                path, msg = request.urlretrieve(
                    file_link, save_path + "/" + download_name, hook.update_to)
                file_name = str(os.path.basename(path))
                return file_name
        except Exception as e:
            Flog.i("下载失败:" + str(e))
            return ""
Пример #29
0
def sign(task: Task, new_mode: bool, sigalg: str = "SHA1withRSA") -> bool:
    if new_mode:
        apkfile = FPath.WORKSPACE_PATH + "/new_mode_output.apk"
    else:
        apkfile = FPath.WORKSPACE_PATH + "/output.apk"
    keystore = FPath.WORKSPACE_PATH + "/" + task.keystore_info.keystore_name
    if not os.path.exists(keystore):
        Flog.i("the keystore file is not exists. " + keystore)
        return False
    sign_shell = java.get_jarsigner_shell(
    ) + " -digestalg SHA1 -sigalg %s -keystore %s -storepass %s -keypass %s %s %s" % (
        sigalg, keystore, task.keystore_info.keystore_password,
        task.keystore_info.keystore_alias_password, apkfile,
        task.keystore_info.keystore_alias)

    return command.exec_command(sign_shell)
Пример #30
0
def remove_files(target: str) -> bool:
    """
    删除文件或文件夹
    :param target: 目标文件或文件夹路径
    :return: 是否成功
    """
    try:
        if isfile(target):
            os.remove(target)
            return True
        else:
            shutil.rmtree(target)
            return True
    except Exception as e:
        Flog.i(str(e))
        return False