【原创】记账软件随手记备份文件解密

查看 205|回复 11
作者:tp522022   
随手记是金蝶公司出品的一款记账软件,个人比较喜欢其中的记账功能,投资模块我是一点兴趣没有,为了减少广告影响我用华为自带的手机管家ban掉了联网权限,为了支付宝和微信的账单可以正常导入到随手记中,对随手记的备份还原功能进行了一波逆向分析,成功实现了账单数据的写入,还原后可在随手记App中正常查阅。
个人使用的用于分析的Android版本号12.69.0.0.
随手记备份出来的kbf文件本质上是个zip文件,随手记备份时将账本数据mymoney.sqlite和用户信息数据backup_info打包为本质为zip的kbf文件.当然这两个文件都有一定程度的魔改backup_info这个不用管到时候原封不动打包回去就行,主要是mymoney.sqlite这个文件的解密。
使用以下Python代码可正常解密解压kbf文件得到sqlite数据库文件
[Python] 纯文本查看 复制代码def unzip_kbf(input_files=None):
    global tp_kbf_file_name
    if input_files is None:
        if global_constant.full_update or global_constant.sdcard_root_path is None:
            input_file_abs_path = os.path.join(tp_path.parent.parent, 'f_input/')
        else:
            input_file_abs_path = os.path.join(global_constant.sdcard_root_path, '.mymoney', 'backup/')
    else:
        if global_constant.full_update or global_constant.sdcard_root_path is None:
            input_file_abs_path = os.path.join(tp_path.parent.parent, 'f_input/', input_files)
        else:
            input_file_abs_path = os.path.join(global_constant.sdcard_root_path, '.mymoney', 'backup/', input_files)
    if not os.path.exists(input_file_abs_path):
        print(f'{input_file_abs_path}不存在')
        raise FileNotFoundError(f'输入文件kbf不存在-->{input_file_abs_path}')
    print(f'输入待解压kbf文件路径:{input_file_abs_path}')
    if os.path.isdir(input_file_abs_path):
        files = os.listdir(input_file_abs_path)
        for f in files:
            if f.endswith('.kbf'):
                global tp_kbf_file_name
                tp_kbf_file_name = f
                zf = zipfile.ZipFile(os.path.join(input_file_abs_path, f))
                zf.extractall(path=os.path.join(tp_path.parent.parent, 'f_input/'))
                break
    elif os.path.isfile(input_file_abs_path):
        if input_files.lower().endswith('.kbf'):
            tp_kbf_file_name = input_files
            zf = zipfile.ZipFile(input_file_abs_path)
            zf.extractall(path=os.path.join(tp_path.parent.parent, 'f_input/'))
        pass
def ssj_kbf_sqlite_convert(input_file=None, output_file=None, convert=ConvertType.Exchanged):
    """
    convert ssj data, after kbf unzip to sqlite,convert it to normal sqlite database file
    :param convert: 0 means convert it auto, 1 kbf format to sqlite, 2 sqlite to kbf format
    :param input_file: the mymoney.sqlite file path
    :param output_file: the convert mymoney.sqlite file path
    :return:
    """
    if input_file is None:
        input_file = os.path.join(tp_path.parent.parent, 'f_input/mymoney.sqlite')
    if output_file is None:
        output_file = os.path.join(tp_path.parent.parent, 'f_output/mymoney.sqlite')
    sqlite_header = (0x53, 0x51, 0x4C, 0x69,
                     0x74, 0x65, 0x20, 0x66,
                     0x6F, 0x72, 0x6D, 0x61,
                     0x74, 0x20, 0x33, 0x0)
    kbf_header = (0x0, 0x0, 0x0, 0x0,
                  0x0, 0x0, 0x0, 0x0,
                  0x0, 0x0, 0x0, 0x0,
                  0x0, 0x46, 0xFF, 0x0)
    if global_constant.print_repeat_data_info:
        read_file_header(input_file)
    if os.path.exists(output_file):
        os.remove(output_file)
    with open(input_file, mode='rb') as f:
        with open(output_file, mode='wb') as fw:
            data_buffer = f.read()
            if data_buffer[0] == 0x53:
                kbf2sqlite = False
                print("当前为SQLite文件格式")
            if data_buffer[0] == 0x00:
                kbf2sqlite = True
                print("当前为KBF文件格式")
            write_buffer = bytearray(data_buffer)
            index = 0
            while index
以上代码先将正常解压kbf文件得到mymoney.sqlite,再修改前16个字节
[Python] 纯文本查看 复制代码    sqlite_header = (0x53, 0x51, 0x4C, 0x69,
                     0x74, 0x65, 0x20, 0x66,
                     0x6F, 0x72, 0x6D, 0x61,
                     0x74, 0x20, 0x33, 0x0)
    kbf_header = (0x0, 0x0, 0x0, 0x0,
                  0x0, 0x0, 0x0, 0x0,
                  0x0, 0x0, 0x0, 0x0,
                  0x0, 0x46, 0xFF, 0x0)
此时得到就是正常可以写入数据的sqlite数据库了。
下面再说随手记中的数据库结构
1. t_transaction 记录了所有交易信息,主要为支出,收入,转账三类
2. t_account 记录账户信息譬如银行卡,支付宝,微信支付等都属于资金流入流出的账户
3. t_category 记录的支出,收入的分类信息
以下是t_transaction的表结构
[SQL] 纯文本查看 复制代码CREATE TABLE "t_transaction" (
        "transactionPOID"        LONG NOT NULL,
        "createdTime"        LONG NOT NULL,
        "modifiedTime"        LONG NOT NULL,
        "tradeTime"        LONG NOT NULL,
        "memo"        varchar(100),
        "type"        integer NOT NULL,
        "creatorTradingEntityPOID"        LONG,
        "modifierTradingEntityPOID"        LONG,
        "buyerAccountPOID"        LONG,
        "buyerCategoryPOID"        LONG DEFAULT 0,
        "buyerMoney"        decimal(12 , 2),
        "sellerAccountPOID"        LONG,
        "sellerCategoryPOID"        LONG DEFAULT 0,
        "sellerMoney"        decimal(12 , 2),
        "lastUpdateTime"        LONG,
        "photoName"        VARCHAR(100),
        "photoNeedUpload"        integer DEFAULT 0,
        "relation"        varchar(200) DEFAULT '',
        "relationUnitPOID"        LONG,
        "ffrom"        varchar(250) DEFAULT '',
        "clientID"        LONG DEFAULT 0,
        "FSourceKey"        varchar(100) DEFAULT NULL,
        "photos"        TEXT,
        "transaction_number"        TEXT,
        "merchant_order_number"        TEXT,
        "import_data_source"        TEXT,
        PRIMARY KEY("transactionPOID")
);
需要注意的是
支出时 buyerAccountID 为支付账号ID buyerCategory留空 sellerAccountID留空 sellerCategory为具体支出类别 type =0
收入时 buyerAccountID 留空 buyerCategory为收入类别 sellerAccountID为账户ID sellerCategory留空 type = 1
转账时 buyerAccountID为资金来源方 sellerAccountID为资金流向方 category均为空,而且会插入两条记录一个type=2一个type=3,这两条记录relation应该一致而FSourceKey不同,否则还原数据时可能导致app闪退
通过支付宝App的账单开具个人流水记录可以导出支付宝账单,同理可导出微信账单。两者都是csv文件自己解析下即可。
最后正常写入数据后,调用上面的ssj_kbf_sqlite_convert函数将sqlite数据库转化为kbf需要的格式,最后导入手机上随手记的备份目录,通过随手记的还原功能可以导入数据

随手, 文件

tp522022
OP
  


Jun01 发表于 2023-9-14 23:17
大佬厉害。
用了好多年随手记,只喜欢用本地功能,也禁止它联网,一直找kbf文件解析密的方法,可 ...

为了导入方便,我装了QPython,直接在手机上运行脚本,贴出来的这一部分脚本就是为了兼容电脑和手机才有各种路径判断的。现在唯一的问题就是pdd订单没有商品详情 目前还在考虑怎么用油猴脚本导出pdd订单的详情信息
bdzwater   


JaySun520 发表于 2023-9-22 08:18
网页端有接口吗?找了一圈没有找到,能否告知一下怎么把随手记上的数据拉取到本地?O(∩_∩)O谢谢了

网页端直接用浏览器F12然后监控流水查看的请求即可,需要注意的是,提交的请求需要用自己的cookie代替,而且会过期,但给你爬数据的时间是足够了,我从10年开始爬,1500多页的数据,也没见超时
bdzwater   

感谢,随手记用了好多年了,不过我一般都是直接用网页端的接口,拉取所有数据到本地做备份,外加一些更加丰富的图表统计等
tp522022
OP
  


bdzwater 发表于 2023-9-13 15:04
感谢,随手记用了好多年了,不过我一般都是直接用网页端的接口,拉取所有数据到本地做备份,外加一些更加丰富的 ...

需求不一样,我是一点网络也不想他连,而且通过随手记内置的支付宝,微信账单导入功能导入时经常出现分类不准的情况
13121039687   

生存手册时长
vivvon   

楼主厉害!
penguin520   

这个很实用,感谢分享
dubuqingyun   

厉害,感谢分享!
wan23   

把kbf文件当zip压缩文件处理
您需要登录后才可以回帖 登录 | 立即注册

返回顶部