扫描全能王文档矫正逆向记录

2023-10-23 00:50

本文主要是介绍扫描全能王文档矫正逆向记录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景

扫描全能王有个功能是将弯曲的文本拉直成平直的文本。在扫描全能王的app上,这个功能的入口在拍书籍的tab。同时在图片编辑页面,也有个按钮可以触发这个功能。它的效果大概如下。

在这里插入图片描述

这篇文章主要介绍如何逆向这个算法

初步定位

对扫描王apk初步逆向之后,发现破解难度有点大。大概有这几个问题

在这里插入图片描述

  • 扫描全能王apk经过爱加密加过壳,ida动态破解难度大,基本一开始挂调试就触发反调试机制
  • 文档矫正算法有两套,其中纯C++实现的算法复杂度极高

加壳的处理直接导致很多逆向手段用不了。而复杂的纯CV又导致还原算法基本不可能。

好在多次尝试之后,发现扫描全能王还有个模型矫正的算法。

模型矫正逆向

扫描全能王在6.0版本之后增加了一个矫正函数。在6.0之前的矫正函数名都是 dewarpXXX,在6.0之后多了一个dewarpXXXNew。比如这个,接受的是一个图片的指针参数。

dewarpImgPtrNew

用ida静态分析该函数之后发现,它使用的是基于MNN推理引擎的模型。
这个模型实现了端到端的图像矫正,而且效果跟传统算法的矫正结果差不多。

把逆向目标定位在这个函数上,难度会小很多。所需要做的事情大概是:

  • 梳理模型矫正的输入数据预处理和后处理
  • dump模型出来
  • 还原矫正流程

逆向模型矫正的好处之一是只要拿到了模型,就成功了一半。

dump模型

虽然扫描全能王把模型以二进制方式打包进了so库,但是没有很好地对二进制数据进行加密。在花了一些时间分析之后,就用ida将模型dump出来了
在这里插入图片描述
初步分析这个模型之后,不得不说扫描全能王的算法团队有点东西。他们用同一个分割网络实现了边缘检测,阴影检测,文档矫正。而这个模型的大小才1M不到。

分析前后处理

预处理的分析比较简单。我构造了模型矫正的上下文环境,通过hook的方式让矫正流程强制走了模型矫正。

    1. int val = initDewarpContext()//初始化引擎2. ScannerEngine.dewarpImgPtrNew(val, ptr)//处理数据3. ScannerEngine.releaseContext(val)//释放引擎

在进入了模型矫正调用之后,还需要hook一些关键函数。
比如,我需要知道输入图像缩放到什么尺寸,它的归一化参数是多少。

而这些需要对so进行静态分析后才能找到合适的hook位置。
举例来说,输入到模型的图像缩放的尺寸,我用这个frida函数实现

Interceptor.attach(resize, {onEnter: function(args) {if(dewarpProcessDone != 1) return;if(Process.getCurrentThreadId() != threadId) return;console.log('\n[-] resize, thread: ', Process.getCurrentThreadId());console.log("[-] resize args[0] - args[4]: ", args[0], args[1], args[2], args[3], args[4]);console.log("[-] resize src size: ", ptr(args[0]).add(4).readPointer(), " \n    src size:", ptr(args[0]).add(4).readPointer().add(8).readInt(), "-", ptr(args[0]).add(4).readPointer().add(12).readInt());console.log("[-] resize dst size: ", ptr(args[2]), " \n    dst size:", ptr(args[2]).readInt(), "-", ptr(args[2]).add(4).readInt());console.log('    args[2]:\n', Memory.readByteArray(ptr(args[2]), 16));console.log('    flag:\n', Memory.readByteArray(ptr(args[0]).add(0x4).readPointer(), 16));

这里涉及到二进制分析,还有对数据结构的了解。展开讲比较复杂,都可以单独开一篇了。总之在分析后知道,模型的输入是240x240。

有些人可能会问,啊模型输入不是看模型文件就知道吗?这个不行,它的MNN文件看不到输入尺寸信息。

预处理的流程不多,解决了输入尺寸,就完成了一大半。

真正难的是后处理的分析

看后处理的代码,至少包含几个步骤。

  1. 输出数据高斯模糊
  2. 平滑处理
  3. 放大插值
  4. 原图映射

光是这几个流程的还原,就花了我小一个月时间。

还原矫正流程

最后还原出来的结果大概是这样:
在这里插入图片描述
扫描全能王的模型矫正,其实是一种位移场矫正算法。
这里我在中间的图用绿色的网格将位移场表示出来,会比较直观。

  • 左边是原图,首先将模型缩放到240x240的尺寸,送进模型
  • 模型会检测图像的曲率,得到一系列离散的曲率值。将这些曲率值连起来,就是中间图的绿色网格
  • 在得到了曲率值之后,将原图的像素一一映射到新的图片,得到最右边的图

位移场矫正的思路大概是这样:

  • 假设有一张平直的图像文档,像最右边的
  • 将它以某种程度扭曲,这种扭曲必须是连续的,不是离散的。那么描述这种扭曲的就是一种位移场
  • 将原图的所有像素,按照这个位移场进行映射,就能得到一张扭曲后的图

可以看到位移场矫正算法,它是一种自然位移的逆运算。能想到这个方案的算法师有点东西,而且这个方案值钱的地方在于需要大量接近真实的数据标注。
目前还不知道这些数据是怎么标注的,如果用Blender造数据,会和真实样张有出入。用真实样张进行标注,又是天量的工作时间。

最后

整个逆向大概花了两三个月时间。最后我用C++还原了这个位移场矫正算法。上面的绿色网格图,就是在还原出来的算法代码上添加的。它其实是逆运算。

简单讲,矫正模型输出的是扭曲->原图的位移数据,我称之为逆位移场。如果将这些数据可视化的话,会不好理解。

我在逆向出来的代码上,将模型的输出数据反向计算,得到一个正的位移场,再将这个位移场套到一个标准的网格上,就能看出来原图是经过怎样的一个扭曲空间,变成一张扭曲过的图的。

这篇关于扫描全能王文档矫正逆向记录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/264666

相关文章

Java操作Word文档的全面指南

《Java操作Word文档的全面指南》在Java开发中,操作Word文档是常见的业务需求,广泛应用于合同生成、报表输出、通知发布、法律文书生成、病历模板填写等场景,本文将全面介绍Java操作Word文... 目录简介段落页头与页脚页码表格图片批注文本框目录图表简介Word编程最重要的类是org.apach

在Spring Boot中集成RabbitMQ的实战记录

《在SpringBoot中集成RabbitMQ的实战记录》本文介绍SpringBoot集成RabbitMQ的步骤,涵盖配置连接、消息发送与接收,并对比两种定义Exchange与队列的方式:手动声明(... 目录前言准备工作1. 安装 RabbitMQ2. 消息发送者(Producer)配置1. 创建 Spr

Python Pillow 库详解文档(最新推荐)

《PythonPillow库详解文档(最新推荐)》Pillow是Python中最流行的图像处理库,它是PythonImagingLibrary(PIL)的现代分支和继承者,本文给大家介绍Pytho... 目录python Pillow 库详解文档简介安装核心模块架构Image 模块 - 核心图像处理基本导入

k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)

《k8s上运行的mysql、mariadb数据库的备份记录(支持x86和arm两种架构)》本文记录在K8s上运行的MySQL/MariaDB备份方案,通过工具容器执行mysqldump,结合定时任务实... 目录前言一、获取需要备份的数据库的信息二、备份步骤1.准备工作(X86)1.准备工作(arm)2.手

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

Python UV安装、升级、卸载详细步骤记录

《PythonUV安装、升级、卸载详细步骤记录》:本文主要介绍PythonUV安装、升级、卸载的详细步骤,uv是Astral推出的下一代Python包与项目管理器,主打单一可执行文件、极致性能... 目录安装检查升级设置自动补全卸载UV 命令总结 官方文档详见:https://docs.astral.sh/

统一返回JsonResult踩坑的记录

《统一返回JsonResult踩坑的记录》:本文主要介绍统一返回JsonResult踩坑的记录,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录统一返回jsonResult踩坑定义了一个统一返回类在使用时,JsonResult没有get/set方法时响应总结统一返回

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

java对接海康摄像头的完整步骤记录

《java对接海康摄像头的完整步骤记录》在Java中调用海康威视摄像头通常需要使用海康威视提供的SDK,下面这篇文章主要给大家介绍了关于java对接海康摄像头的完整步骤,文中通过代码介绍的非常详细,需... 目录一、开发环境准备二、实现Java调用设备接口(一)加载动态链接库(二)结构体、接口重定义1.类型

C#实现将Office文档(Word/Excel/PDF/PPT)转为Markdown格式

《C#实现将Office文档(Word/Excel/PDF/PPT)转为Markdown格式》Markdown凭借简洁的语法、优良的可读性,以及对版本控制系统的高度兼容性,逐渐成为最受欢迎的文档格式... 目录为什么要将文档转换为 Markdown 格式使用工具将 Word 文档转换为 Markdown(.