【专题文章】语言包的结构和IDC文件的使用
语言包的结构和IDC文件的使用作者:coollang
在家里过年的时候收到张斌的Email,问起语言包的结构,那是因为手边没有资料,而且上网很不方便,只能作罢。我是11号才开始上班的,开始一直没有时间,所以积在周末把它发上来。
这里主要说一下语言包的结构,同时还有IDC文件的使用。IDC是IDA支持的一种类C的脚本语言,我以前也没有用过,恰好在国外的网站上发现了几个例子,于是发上来,给大家提供参考。这确实是很实用的一种东西。
西门子的语言包里面可能包含多个语言,而字串是压缩过的,其主要是对高频词组进行了压缩。同时对字串采用索引存储,即建立一个索引表。索引表中存放一个字串组(8个字串)的地址,字串组内部是一个字串链表。通过字串ID可以得到字串所在的字串组在索引表中的位置,然后根据索引找到字串组的地址。在字串组的内部通过顺序的查找链表来找到压缩后的字串。需要注意的是从压缩后的字串解压缩后的得到的并不是真正的字符串(GB或UNICODE),而是Siemens的内部格式的东西,还要作相应的转换才能得到Unicode字串。我写过的Sie2Uni就是作这个用的。西门子的这种存储方式兼顾了效率与空间的平衡,是一种不错的做法。细节如下,更多可参照Siemens Language Editor和Flash程序。
UploadFile/200422118592389018.jpg
这个例子Lang_unpack_data.idc是一个解包siemens语言包的IDC文件,可以在IDA中生成对应的字串以及在Names window中生成标示(通过内值函数)。具体的语法可以查看IDA的帮助中IDC部分,熟悉C的应该没什么难度。而且可以很容易的转换为C程序。此程序我已经作了相当多的注释,应该很容易看懂。其实这个程序的算法就是Flash中的对应部分,我会把它一并附上。程序如下(抱歉,对应网站是非英语论坛,我不能得到作者,但是类似的程序我早已独立实现过):
使用方法是在IDA的File->IDC File(或F2),加载相应的IDC文件
#include <idc.idc>
//请根据需要除去对应的注释,其他未列出的可以通过在FuBu中查找Hex格式Byte
//“BBBB0000“,这是语言包的标志,需要注意的是这里的地址是对应16M空间的地址,
//请自行调整。
#define LGP_BASE 0xE6C000 //6688
//#define LGP_BASE 0xB00000 //x618
//#define LGP_BASE 0x7A0000 //M55c
//#define LGP_BASE 0xE00000 //S57c
//解压缩函数,lang->语言ID,ea->字串开始地址 字串的存储格式为BYTE(字串长度,字串内容。。。)
static unpack(lang,ea){
auto lgp_ea,lgp_ea2,uni,o_lginfo,len,pos,s,blen,c,dec,ea1;
lgp_ea=LGP_BASE;
o_lginfo=Word(lgp_ea+0xA);//语言Info表Offset
len=Byte(ea); //取得字串长度(并不是真实的长度,而是压缩后的长度)
//以下几行是在IDA中处理对应BYTE的格式
for (pos=ea;pos<ea+len;pos++)MakeUnkn(pos,1);
if(len<=4)
MakeArray(ea,len);
else{
MakeArray(ea,4);
MakeArray(ea+4,len-4);
}
lgp_ea=LGP_BASE+o_lginfo;//语言Info表的Base地址
lgp_ea2=lgp_ea+14*lang; //对应语言的的Info表地址,每个Info表的大小是14个Byte
//解压缩字串
s="";uni=0; //s为最终字串
for(pos=1;pos<len;pos++){
c=Byte(ea+pos); //取得压缩后的Byte
blen=0; //压缩前的Byte长度
dec=0;
while(c>=Word(lgp_ea2+2+blen*4)){ //取得压缩后Byte所对应的压缩表中的信息
dec=Word(lgp_ea2+2+blen*4);//取得压缩表中的对应地址。压缩过程一般最多压缩4字符。压缩表分别是
//四字符压缩表,三字符压缩表,二、一字符压缩表
blen++;
if(blen==4) break;
}
ea1=LGP_BASE+Word(lgp_ea2+4*blen)+(c-dec)*(blen+1); //取得压缩Byte所对应的解压缩后的字符(1到4个字符)地址
//以下输出压缩Byte所对应的解压缩后字符,并对特殊字符作相应的转换
do{
c=Byte(ea1);
if((c>=0x20 && c<0x80 && uni==0) || (c>0x10 && c<0x80 && uni>0)){
if (c+uni<0x1B0)
s=s+form("%c",c+uni);
else
s=s+form("%c",c+uni+0x30);
} else {
s=s+form("<%02X>",c);//先用<>输出特殊字符的BYTE值
//以下或者是一些前导字符或者是特殊字符,需要作相应的转换
if (c==0x9B) uni=0x170;
if (c==0x96) uni=0x80;
if (c==0x97) uni=0x100;
if (c==0x95 || c==0x91) uni=0x0;
if (c==0x8a || c==0x0d) s=s+"\n";
}
ea1++;
blen--;
} while(blen>=0);
}
MakeRptCmt(ea,s); //在标示名字的地址出输出对应的字符
if (lang>0) MakeName(ea,""); //非英语语言输出空(可能考虑到Unicode字符问题)
}
//在字串组内查找次序为n的字串的地址
static shift(ea,n){
while(n--){
ea=ea+Byte(ea);
}
return ea;
}
static main(void){
auto nLangs,lang_id,lll,ref,ea1,ceil,mnem,op1,op2,msg_id,idx1,idx2,ea2,eap,i,sadd,npara,o_msgidx,mea,v,max_id;
npara =Word(LGP_BASE+6); //语言包的Page数量(C166不能跨Page边界)
o_msgidx=Word(LGP_BASE+0x12); //字串组索引表的Offset,字串索引表以Word为单位,存储字串组的Page内Offset。
max_id=Word(LGP_BASE+0x2a); //最大字串ID
nLangs=Word(LGP_BASE+0xE); //语言数量(英文、简体中文…)
for (msg_id=0;msg_id<=max_id;msg_id++){
for (lang_id=0;lang_id<nLangs;lang_id++){
eap=LGP_BASE+0x3c; //ID范围->Page表
sadd=0; //Page
for(i=1;i<npara;i++){ //查找字串的所在Page
if((msg_id*nLangs+lang_id)<Word(eap)) break;
eap=eap+2;
sadd++;
}
v=(msg_id*nLangs+lang_id)/8; //字串组索引表的ID,每8个一组。每组内用链表存储
idx2=(msg_id*nLangs+lang_id)%8; //组内次序
mea=Word(LGP_BASE+o_msgidx+v*2)+LGP_BASE+sadd*0x4000; //计算字串内容开始地址,基地址+Page地址+OffsetInPage,
//最后一项是从字串组索引表中查询得到
mea=shift(mea,idx2); //找到对应字串的地址
unpack(lang_id,mea); //解压缩相应字串。因为语言包对字符进行了压缩,对高频词组进行了压缩。
if (lang_id==0)
//如果需要10进制的ID,可以在下面修改。
if(!MakeName(mea,form("Lgp_str_%03X",msg_id)))return; //如果是英文(默认是语言0),则输出Name。
Jump(mea);
}
}
}
//在6688Flash中的实现
0xE0:3EFA ; ★★★★★★★★ S U B R O U T I N E★★★★★★★★★★★★★★★★★★★
0xE0:3EFA GetStringByID: ; CODE XREF: 0xC7:88B6P
0xE0:3EFA ; sub_E1FCE8+30P
0xE0:3EFA push r6
0xE0:3EFC mov r6, #0FE04h
0xE0:3F00 extp #37h, #1 ; '7'
0xE0:3F04 mov r10, word_DCEF2 ; R10 -> Cur LgInfo Table
0xE0:3F08 extp #37h, #1 ; '7'
0xE0:3F0C mov r2, word_DCEF8 ; R2 -> CurrentLgID
0xE0:3F10 scxt DPP0, #39Bh
0xE0:3F14 ; assume dpp0: 39Bh (page 0xE6C000)
0xE0:3F14 push DPP2
0xE0:3F16 mov r1, #0Eh ; Language Count
0xE0:3F18 mov r3,
0xE0:3F1A mulu r12, r3
0xE0:3F1C mov r12, MDL
0xE0:3F20 add r12, r2
0xE0:3F22 or r13, #8000h
0xE0:3F26 mov r15, #39Bh
0xE0:3F2A mov r1, #6 ; Paragraphs Count
0xE0:3F2C mov r2,
0xE0:3F2E sub r2, #1
0xE0:3F30 mov r3, #3Ch ; '<' ; Current paragraphs
0xE0:3F34 loc_E03F34: ; CODE XREF: GetStringByID+48j
0xE0:3F34 mov r5, ; 找到对应的段
0xE0:3F36 cmpd1 r2, #0
0xE0:3F38 jmpr cc_Z, loc_E03F44
0xE0:3F3A cmp r12, r5 ; R12 -> ID*LgCount + LgID
0xE0:3F3C jmpr cc_C, loc_E03F44
0xE0:3F3E add r15, #1 ; R15 -> Current Page
0xE0:3F40 add r3, #2
0xE0:3F42 jmpr cc_UC, loc_E03F34 ; 找到对应的段
0xE0:3F44 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xE0:3F44 loc_E03F44: ; CODE XREF: GetStringByID+3Ej
0xE0:3F44 ; GetStringByID+42j
0xE0:3F44 mov , r15
0xE0:3F46 mov r1, r12
0xE0:3F48 shr r1, #3
0xE0:3F4A shl r1, #1
0xE0:3F4C mov r2, #12h ; Offset of All MsgID Offset
0xE0:3F50 add r1,
0xE0:3F52 mov r4,
0xE0:3F54 or r4, #8000h
0xE0:3F58 mov r5, r12
0xE0:3F5A and r5, #7
0xE0:3F5C jmpr cc_UC, loc_E03F64
0xE0:3F5E ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xE0:3F5E loc_E03F5E: ; CODE XREF: GetStringByID+6Cj
0xE0:3F5E movb rl1, ; 遍历链表,查找String位置
0xE0:3F60 movbz r1, rl1
0xE0:3F62 add r4, r1
0xE0:3F64 loc_E03F64: ; CODE XREF: GetStringByID+62j
0xE0:3F64 cmpd1 r5, #0
0xE0:3F66 jmpr cc_NZ, loc_E03F5E ; 遍历链表,查找String位置
0xE0:3F68 movb rl3, ; RL3 -> Length,FirstByte
0xE0:3F6A mov r11, ; R11 -> InfoTable
0xE0:3F6C calls 0E0h, UnpackLngString
0xE0:3F70 mov , r14
0xE0:3F72 nop
0xE0:3F74 movb , word_FF1C
0xE0:3F78 pop DPP2
0xE0:3F7A pop DPP0
0xE0:3F7C ; assume dpp0: 0FFFFh (page 0x3FFFC000)
0xE0:3F7C pop r6
0xE0:3F7E rets
0xE0:3F80 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xE0:3F80 loc_E03F80: ; CODE XREF: UnpackLngString+4j
0xE0:3F80 movb rl2,
0xE0:3F82 movbz r2, rl2
0xE0:3F84 mov , r14
0xE0:3F86 mov r1,
0xE0:3F8A cmp r2, r1
0xE0:3F8C jmpr cc_NC, loc_E03F94
0xE0:3F8E mov r5, r11
0xE0:3F90 add r5, r2
0xE0:3F92 jmpr cc_UC, loc_E03FE8
0xE0:3F94 ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xE0:3F94 loc_E03F94: ; CODE XREF: 0xE0:3F8Cj
0xE0:3F94 mov r1,
0xE0:3F98 cmp r2, r1
0xE0:3F9A jmpr cc_NC, loc_E03FAE
0xE0:3F9C mov r5, r2
0xE0:3F9E mov r1,
0xE0:3FA2 sub r5, r1
0xE0:3FA4 shl r5, #1
0xE0:3FA6 mov r1,
0xE0:3FAA add r5, r1
0xE0:3FAC jmpr cc_UC, loc_E03FE4
0xE0:3FAE ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xE0:3FAE loc_E03FAE: ; CODE XREF: 0xE0:3F9Aj
0xE0:3FAE mov r1,
0xE0:3FB2 cmp r2, r1
0xE0:3FB4 jmpr cc_NC, loc_E03FCC
0xE0:3FB6 mov r5, r2
0xE0:3FB8 mov r1,
0xE0:3FBC sub r5, r1
0xE0:3FBE mov r1, r5
0xE0:3FC0 shl r5, #1
0xE0:3FC2 add r5, r1
0xE0:3FC4 mov r1,
0xE0:3FC8 add r5, r1
0xE0:3FCA jmpr cc_UC, loc_E03FE0
0xE0:3FCC ; ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0xE0:3FCC loc_E03FCC: ; CODE XREF: 0xE0:3FB4j
0xE0:3FCC mov r5, r2
0xE0:3FCE mov r1,
0xE0:3FD2 sub r5, r1
0xE0:3FD4 shl r5, #2
0xE0:3FD6 mov r1,
0xE0:3FDA add r5, r1
0xE0:3FDC movb ,
0xE0:3FDE add r5, #1
0xE0:3FE0 loc_E03FE0: ; CODE XREF: 0xE0:3FCAj
0xE0:3FE0 movb ,
0xE0:3FE2 add r5, #1
0xE0:3FE4 loc_E03FE4: ; CODE XREF: 0xE0:3FACj
0xE0:3FE4 movb ,
0xE0:3FE6 add r5, #1
0xE0:3FE8 loc_E03FE8: ; CODE XREF: 0xE0:3F92j
0xE0:3FE8 movb ,
0xE0:3FEA ; ★★★★★★★★ S U B R O U T I N E★★★★★★★★★★★★★★★★★★★
0xE0:3FEA UnpackLngString: ; CODE XREF: GetStringByID+72P
0xE0:3FEA mov , r15
0xE0:3FEC subb rl3, #1
0xE0:3FEE jmpr cc_NZ, loc_E03F80
0xE0:3FF0 rets
0xE0:3FF0 ; End of function UnpackLngString
附件:
Lang_unpack_data.idcviewfile.asp?ID=9889
[此贴子已经被作者于2004-2-21 19:00:18编辑过] 大家风范!!!!!!
老大,就是老大!!!!!!!!!!!!!!!!!111 签到,慢慢研究 收下先 签到。 不愧大师!
很怀念SL456688i,他现在还好吗? 触角越来越广了,小8事业发展中…… 收到,我也要慢慢研究!!! 哇
收到
多谢狼大 狼大就是狼大!!
厉害
!!!!!!!!!!!!!!!!! 狼大的帖子那是必定要顶的!!!!!!!!!!!!!!!!!
页:
[1]