批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程
[批处理文件精品]批处理版照片整理器[批处理文件精品]纯批处理备份&还原驱动在线第三方下载
返回列表 发帖

[原创教程] 有道离线字典的拆解

本帖最后由 523066680 于 2016-6-8 22:42 编辑

去年就开始拆了,发现译文信息里一部分翻译是明文,一部分又是给出了另一个字典的索引
要自己挖,还分层的挖,烦了就停了。今年想起来又接着搞,挖成明文后对数据格式化,改
成Perl的hash/array复合结构。分成了五六个脚本吧,拆解部分不一一张贴,主要说方法。

准备

        安装 有道字典增强版 (下载的V6.2),安装目录下会有 localdicts 文件夹,包含字典文
    件以及索引文件。
    1. C:\USERS\%USERNAME%\APPDATA\LOCAL\YOUDAO\DICT\APPLICATION\LOCALDICTS
    2.     2016/06/06  09:20    <DIR>          ..
    3. 2016/06/06  09:20        28,460,334 21EC.ydic
    4. 2016/06/06  09:20         8,094,269 basicCE.ydic
    5. 2016/06/06  09:20        16,692,913 basicEC.ydic
    6. 2016/06/06  09:20         3,737,882 CE.idx
    7. 2016/06/06  09:20               250 CE.ifo
    8. 2016/06/06  09:20         7,991,892 EC.idx
    9. 2016/06/06  09:20               334 EC.ifo
    10. 2016/06/06  09:20         9,900,103 newCE.ydic
    11. 2016/06/06  09:20         5,475,078 phrase.ydic
    12. 2016/06/06  09:20        42,980,352 sentenceDict.sql
    复制代码
    .ifo 文件是摘要信息(比如某个字典有多少单词量)
    .idx 文件分两部分,第一部分是索引数据,第二部分是单词内容
    .ydic 文件是翻译信息

分析

        先针对英汉字典(EC.idx basicCE.ydic)

        比较业余,用了几种方法,就.idx文件来说,已经知道是索引,将其转成16进制按N组一行的方式
    排列(用的Perl提取划分,虽然我知道有些工具更好用),发现其中的规律是,每12个字节为一组
    数据,在一组里面,每4个字节合为一个数值(低位在前,这是后来发现的)。以及按4列16进制值显示后
    发现到了某个位置规律就不一样了。
    1. 1057288 16 6a 39 00
    2. 1057289 83 b6 fe 00
    3. 1057290 17 00 00 00
    4. 1057291 1b 6a 39 00
    5. 1057292 9a b6 fe 00
    6. 1057293 17 00 00 00  //以下为第二部分,没有明显规律
    7. 1057294 37 73 71 65
    8. 1057295 63 75 37 73
    9. 1057296 75 60 64 37
    10. 1057297 74 7f 72 75
    11. 1057298 37 74 62 79
    复制代码
    然后对ydic分析字节频率,以下是频率较高的字节,左边是出现的次数
    00337934 ac
    00352074 6d
    00352432 6b
    00378084 22
    00477148 f5
    00563980 2a
    00567693 75
    00692001 21
    00997268 33
    02211802 32

    然而并没有什么卵用,6d 和 6b 33 和 32 是什么? m k 3 2 ?写了一个脚本: 输入16进制值,试转UTF、GBK
    1. input:6d 6b 33 32
    2. mk32    gbk     109
    3. mk32    big5    109
    4. mk32    utf8    109
    5. 歭社    utf16-le        27501
    6. not utf16-be
    复制代码
    但是好在想起了单词数量,在ifo文件:WordCount:352431
    6b 和 6d的出现次数和这个非常接近,可能作为分隔符。


解码:

    随便指定一个单词,比如 area,用类似二分法的方式,断开网络,对ydic翻译文件对半裁剪。
    用有道词典查询该单词,不能查到就提取另一半/继续对半裁剪,最后定位数据:
    6b 32 60 32 2a 32 37 de a5 d9 89 62 79 d9 89 32 3c 32 75 32 2a 4b 32 7e 3e 33 33 30 f5 9c aa f5 8f 8f ff ac 9c
    f5 8c a0 f5 9c aa ff ac 8b f9 8d b2 f7 b7 bf ff ac 8b f8 9c 93 f5 8b a4
    32 4d 3c 32 75 68 32 2a 32 21 33 22 26 22 29 27
    29 23 26 33 26 20 20 32 3c 32 75 68 32 2a 32 22 33 23 26 23 26 23 29 23 33 23 21 27 23 32 6d

    offset: 0d6130
    length: 0x6c

    将翻译内容:“n. 区域,地区;面积;范围”, 试转为不同编码
    gbk: 6e 2e 20 c7 f8 d3 f2 a3 ac b5 d8 c7 f8 a3 bb c3 e6 bb fd a3 bb b7 b6 ce a7
    big5: 6e 2e 20 3f b0 ec a1 41 a6 61 3f a1 46 ad b1 3f a1 46 ad 53 3f
    utf8: 6e 2e 20 e5 8c ba e5 9f 9f ef bc 8c e5 9c b0 e5 8c ba ef bc 9b e9 9d a2 e7 a7 af ef bc 9b e8 8c 83 e5 9b b4
    utf16-le: 6e 0 2e 0 20 0 3a 53 df 57 c ff 30 57 3a 53 1b ff 62 97 ef 79 1b ff 3 83 f4 56

    总结出:采用UTF8编码,并做了简单的处理,hex的高位如果是奇数,高位-1,否则高位+1 , 还原数据:
    {"p":"'εəriə","e":["n.## 区域,地区;面积;范围"],"ex":"1#26297936#600","ex":"2#3636393#3173"}

    "ex":"1#26297936#600"  表示引用字典 21EC.ydic 的数据,offset 为 26297936,600是数据长度
    "ex":"2#3636393#3173" 表示引用字典 phrase.ydic的数据,offset 为 3636393,3173是数据长度

    用二分法锁定字节区域是碰了运气,因为有很多数据都是引用另一个字典,再绕一点都会烦得不行。


现在回去看idx文件:

好像也是通过对半截取的方式,找到了对应的单词,因为,如果单词或者索引删掉了,会导致搜不到。
(去年探索的,具体忘了。。。)加密方式和译文的一样。

总结:
     idx文件,第一部分为索引,索引数据长度 = 352431(单词量) * 12(数据段) = 4229172
4个字节为一个值,低位在前。后面部分为单词,单词部分没有划分符,根据索引进行提取划分,
单词部分采用非常简单的加密:高位奇数时-1,偶数时+1

00 00 00 00 第一单词起点
00 00 00 00 译文起点
16 00 00 00 译文长度
06 00 00 00 第二单词起点
16 00 00 00 译文起点
16 00 00 00 译文长度
0b 00 00 00 。。。
2c 00 00 00
16 00 00 00

拆解
此处略过,因为是不同时间去折腾的,分了多个脚本和步骤,再整理一遍真是烦

转为明文后的字典下载地址

http://523066680.ys168.com/ [临时]文件夹
Youdao_En_Cn_PerlStruct 202016-06.7z
Youdao EN2CN OneFile 2016-06.7z

字典搜索示例
  1. use Encode;
  2. use YAML 'Dump';
  3. my $PATH = "D:\\Local\\Dict\\Youdao\\Analyse_EC";
  4. open READ,"<:raw", "$PATH\\EN2CN.txt";
  5. my $s;
  6. our $data;
  7. while ($s = <READ>)
  8. {
  9.     if ($s=~/^words :/i)
  10.     {
  11.         $s=~/^(.+) \: (.*)\r?\n/i;
  12.         eval "\$data = $2";
  13.         delete $data->{'pr'};      #不显示“相关词组”信息
  14.         print utf8_to_gbk( Dump($data) );
  15.     }
  16. }
  17. close READ;
  18. sub utf8_to_gbk
  19. {
  20.     return encode('gbk', decode('utf8', $_[0]));
  21. }
复制代码
显示结果
---
e:
  - n. 字(word的复数);话语;言语
  - v. 用言语表达(word的三单形式)
p: w?:dz


音标包含一些gbk以外的符号,在终端显示不全
2

评分人数

综合型编程论坛
Writing Code That Nobody Else Can Read.

本帖最后由 523066680 于 2016-6-7 12:38 编辑

我觉得我花了好多时间做了一件非常没有意义的事情……  但是做了又想把它做完整。
现在我可以在终端快速取词了 grep也行,perl脚本也行(平均0.5秒),后台不需要多开一个翻译软件,不需要网络通畅

感谢有道词典没有用什么更进一步的加密。
其他离线字典比如词霸、图灵格斯、bing、海词 的,因为知识量不够所以放弃了
综合型编程论坛
Writing Code That Nobody Else Can Read.

TOP

本帖最后由 codegay 于 2016-6-7 16:28 编辑

你真是太NB了。

sqlite3的应用很普遍。
这篇博客写的5.x 有点老了。http://www.cnblogs.com/catcherx/p/3269628.html

sentenceDict.sql 里的东西是什么?
1

评分人数

去学去写去用才有进步。安装python3代码存为xx.py 双击运行或右键用IDLE打开按F5运行

TOP

本帖最后由 523066680 于 2016-6-7 17:42 编辑

回复 3# codegay


    sentenceDict.sql  全是句子,记得当时也用数据库软件打开看过。明文。
综合型编程论坛
Writing Code That Nobody Else Can Read.

TOP

厉害,要是战争年代就是密码破译的天才。
1

评分人数

TOP

回复 3# codegay
sqlite相当不错,安卓几乎都是这种轻型数据库。功能单一,很适合做单机。

TOP

可惜没有现成程序
每次回帖、谢谢!辛苦了。

TOP

灵格斯有现成的软件搞定
每次回帖、谢谢!辛苦了。

TOP

返回列表