2020年天山固网杯-misc-1

2 分钟阅读

环境

  • OS:Arch Linux
  • Tools:jTessBoxEditor,tesseract-ocr

解题思路

下载题目解压缩后会得到两个文件夹 testtrain,里面全是诸如下图的16进制图片

16进制图片

查看test 内的 0.jpg1.jpg 可以发现 FFD8 FFE0 ,这是jpg图片的16进制文件头。所以此题大概率是需要将 test 中的图片按文件名顺序提取16进制数并将其转化为jpg图片。

首先我们需要提取图片中的16进制数,网上搜到比较好的开源软件是这个tesseract-ocr(这里不详细讲解如何安装,请自行百度)。但是tesseract识别提取出的图中内容与实际误差很大,数据几乎不可用。这里我们需要用到jTessBoxEditor(需要Java环境,下载链接:https://sourceforge.net/projects/vietocr/files/jTessBoxEditor/)来对tesseract进行训练以用来识别图中内容,大致需要以下几步。

  1. 准备样本
    • 这里我们需要 train 文件夹内的图片数据,因为它们的文件名就是图片内容所以比较好用作训练样本,样本需要取到图片内出现的所有的数字和字母(0-9 and A-F)。
    • 我选取的是 0077.jpg1624.jpg3589.jpgAECF.jpgB39D.jpg ,将它们复制到 train_1 文件夹中。
  2. Merge样本文件
    • 启动jTessBoxEditor,依次点击Tools–>Merge TIFF 进入 train_1 中选中所有图片(注意:Files of Type需要选中为 All image Files)文件名改为 num.font.exp0.tif

    jTessBoxEditor

  3. 生成BOX文件
    • 进入num.font.exp0.tif所在目录内
    • 执行下面的命令
      tesseract num.font.exp0.tif num.font.exp0 batch.nochop makebox
       【语法】:tesseract [lang].[fontname].exp[num].tif [lang].[fontname].exp[num] batch.nochop makebox  
       【语法】:lang为语言名称,fontname为字体名称,num为序号;在tesseract中,一定要注意格式
      
    • 操作截图,warning处可忽略 生成BOX文件
  4. 字符矫正
    • num.font.exp0.tif,生成的num.font.exp0.box文件放在同一个目录下
    • 打开 jTessBoxEditor>【BOX Editor】> 【Open】,打开num.font.exp0.tif;矫正【Char】上的字符
    • 操作截图(注意:page有多个,需要挨个矫正,修改后需要保存) 字符矫正
    • 最后替换原来的box文件
  5. 创建一个shell脚本并写入以下内容
     echo Run Tesseract for Training.. 
     tesseract num.font.exp0.tif num.font.exp0 nobatch box.train 
    
     echo Compute the Character Set.. 
     unicharset_extractor num.font.exp0.box 
     mftraining -U unicharset -O num.unicharset num.font.exp0.tr 
    
    
     echo Clustering.. 
     cntraining num.font.exp0.tr 
    
     echo rename Files.. 
     mv normproto num.normproto 
     mv inttemp num.inttemp 
     mv pffmtable num.pffmtable 
     mv shapetable num.shapetable  
    
     echo Create Tessdata.. 
     combine_tessdata num. 
    
     echo done
    
  6. 拷贝num.trainddata文件
    • 将num.trainddata 复制到trsseract-orc 安装目录下的 tessdata 文件夹。下图为我的tessdata文件夹所在路径,每个人的情况不同,请视情况而定。 拷贝num.trainddata文件
    • 现在能看一下训练的情况如何 识别情况
    • 能看出来tesseract能够识别出图片内的16进制并提取出来

接着需要批量提取 test 内图片的内容,这里我用的是一个shell脚本

#!/bin/sh

str=""
for img in `ls test | sort -h`
do
        str+=`tesseract 'test/'$img stdout -l num`
		echo $str >> hex
done

如果使用我的脚本,那么你需要去除空行以及换行符。

最后就是转换jpg图片了,这里用的是网上的java代码

package com.company;

import javax.imageio.stream.FileImageOutputStream;
import java.io.*;

public class test {
    /**
     * 十六进制字节转字节数组
     * Creates byte array representation of HEX string.<br>
     * http://www.cnblogs.com/qgc88
     * @param s
     *            string to parse
     * @return
     */
    public static byte[] fromHexString(String s) {
        int length = s.length() / 2;
        byte[] bytes = new byte[length];
        for (int i = 0; i < length; i++) {
            bytes[i] = (byte) ((Character.digit(s.charAt(i * 2), 16) << 4) | Character
                    .digit(s.charAt((i * 2) + 1), 16));
        }
        return bytes;
    }

    /**
     * Creates HEX String representation of supplied byte array.<br/>
     * Each byte is represented by a double character element from 00 to ff
     * 实现字节数组向十六进制的转换方法一 http://www.cnblogs.com/qgc88
     * @param fieldData
     *            to be tringed
     * @return
     */
    public static String toHexString(byte[] fieldData) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < fieldData.length; i++) {
            int v = (fieldData[i] & 0xFF);
            if (v <= 0xF) {
                sb.append("0");
            }
            sb.append(Integer.toHexString(v));
        }
        return sb.toString();
    }

    //byte数组转图片 http://www.cnblogs.com/qgc88
    public static void byte2image(byte[] data,String path){
        if(data.length<3||path.equals("")) return;
        try{
            FileImageOutputStream imageOutput = new FileImageOutputStream(new File(path));
            imageOutput.write(data, 0, data.length);
            imageOutput.close();
            System.out.println("Make Picture success,Please find image in " + path);
        } catch(Exception ex) {
            System.out.println("Exception: " + ex);
            ex.printStackTrace();
        }
    }


    public static void main(String[] args) {
		String str2="这里是提取出来的16进制字符串"
        byte[] t=fromHexString(str2);
        byte2image(t, "/home/flyingmcdonald/1.jpg");//转成保存图片


	/********************图片转十六进制******************************/
        try
        {
            StringBuffer sb = new StringBuffer();
            FileInputStream fis = new FileInputStream("/home/flyingmcdonald/1.jpg");
            BufferedInputStream bis = new BufferedInputStream(fis);
            java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
            byte[] buff = new byte[1024];
            int len = 0;
            while ((len = fis.read(buff)) != -1)
            {
                bos.write(buff, 0, len);
            }
            // 得到图片的字节数组
            byte[] result = bos.toByteArray();
            System.out.println("++++" + toHexString(result));
            // 字节数组转成十六进制

            String str = toHexString(result);
            //String str = byte2HexStr(result);
            /* http://www.cnblogs.com/qgc88
             * 将十六进制串保存到txt文件中
             */
            PrintWriter pw = new PrintWriter(
                    new FileWriter("qgc88.txt"));
            pw.println(str);
            pw.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}

不出意外的话,你会得到一个内涵flag的图片,然后你就可以快活了,嘿嘿嘿(>v<)

flag.jpg

如果此篇文章有帮到你,请留个言吧。

do,一个从事着word工程师工作的计算机专业菜鸡卑微的请求着。QAQ

如果文中有什么不对或者不清楚的地方,欢迎指正。

参考网址:https://blog.csdn.net/qq_40147863/article/details/82290015

标签: ,

分类:

更新时间:

留下评论