2020年天山固网杯-misc-1
环境
- OS:Arch Linux
- Tools:jTessBoxEditor,tesseract-ocr
解题思路
下载题目解压缩后会得到两个文件夹 test
和 train
,里面全是诸如下图的16进制图片
查看test
内的 0.jpg
和 1.jpg
可以发现 FFD8 FFE0
,这是jpg图片的16进制文件头。所以此题大概率是需要将 test
中的图片按文件名顺序提取16进制数并将其转化为jpg图片。
首先我们需要提取图片中的16进制数,网上搜到比较好的开源软件是这个tesseract-ocr(这里不详细讲解如何安装,请自行百度)。但是tesseract识别提取出的图中内容与实际误差很大,数据几乎不可用。这里我们需要用到jTessBoxEditor(需要Java环境,下载链接:https://sourceforge.net/projects/vietocr/files/jTessBoxEditor/)来对tesseract进行训练以用来识别图中内容,大致需要以下几步。
- 准备样本
- 这里我们需要
train
文件夹内的图片数据,因为它们的文件名就是图片内容所以比较好用作训练样本,样本需要取到图片内出现的所有的数字和字母(0-9 and A-F)。 - 我选取的是
0077.jpg
,1624.jpg
,3589.jpg
,AECF.jpg
,B39D.jpg
,将它们复制到train_1
文件夹中。
- 这里我们需要
- Merge样本文件
- 启动jTessBoxEditor,依次点击Tools–>Merge TIFF 进入
train_1
中选中所有图片(注意:Files of Type需要选中为 All image Files)文件名改为num.font.exp0.tif
- 启动jTessBoxEditor,依次点击Tools–>Merge TIFF 进入
- 生成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处可忽略
- 字符矫正
- num.font.exp0.tif,生成的num.font.exp0.box文件放在同一个目录下
- 打开 jTessBoxEditor>【BOX Editor】> 【Open】,打开num.font.exp0.tif;矫正【Char】上的字符
- 操作截图(注意:page有多个,需要挨个矫正,修改后需要保存)
- 最后替换原来的box文件
- 创建一个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
- 拷贝num.trainddata文件
- 将num.trainddata 复制到trsseract-orc 安装目录下的 tessdata 文件夹。下图为我的tessdata文件夹所在路径,每个人的情况不同,请视情况而定。
- 现在能看一下训练的情况如何
- 能看出来tesseract能够识别出图片内的16进制并提取出来
- 将num.trainddata 复制到trsseract-orc 安装目录下的 tessdata 文件夹。下图为我的tessdata文件夹所在路径,每个人的情况不同,请视情况而定。
接着需要批量提取 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<)
如果此篇文章有帮到你,请留个言吧。
do,一个从事着word工程师工作的计算机专业菜鸡卑微的请求着。QAQ
如果文中有什么不对或者不清楚的地方,欢迎指正。
参考网址:https://blog.csdn.net/qq_40147863/article/details/82290015
留下评论