Bennie 发表于 2005-8-14 00:00:00

【Patch相关】西门子X65系列Patch教程

西门子X65系列Patch教程
从X65起,基于性能和扩展性的要求,西门子抛弃之前使用的E-GOLD结构的一体化芯片(核C166),而是使用了英飞凌公司的新的单芯片IC架构S-GOLDlite -- PMB8875 ,此芯片集成了ARM和DSP,使用基于ARM926的处理器!
ARM而不是C166,这让曾经的Patcher们很受伤,不过不要流泪,经过我初期的研究,除了指令以外,其他的东西大同小异!也就是说,西门子仍然使用原来的系统架构,这些包括资源的存储格式和大部分系统函数。当然大家需要重新学习ARM的汇编指令了,不过当初接触C166的时候也不是一穷二白么?而且可以预料,西门子在以后将一直使用ARM架构的处理器。
ARM是32位的芯片,具有26位的代码空间和32位数据数据空间,同时指令又分为32位ARM指令集和16位的Thumb指令集。ARM指令集都是32位的指令,代码密度低,但是效率高。而Thumb指令集代码密度高(16位指令),依然保持了基本的效率。是ARM的子集,所有的ARM指令都是可以条件执行的,而Thubm只有一条指令又条件执行。ARM和Thumb指令可以相互调用,开销几乎为零(以上引自《ARM常用指令集和汇编》)。这也是需要注意的地方,系统根据当前的T寄存器是否为1来决定是否处于Thumb模式。一些指令可以改变这个寄存器,大多数是根据指令机器字中的某些位。这些内容可以从ARM的处理器手册中的到,要详细地多,由每一条指令的解释和解码过程,应该属于Patch必备。
X65系列使用32M的Flash芯片(EEP是Flash中的特定区域),RAM8M(herrliu语),此外还包括OTP部分,写有IMEI信息,还有其他我不了解的,和以前的系列一样,西门子用Flash的部分区域来做了一个FAT16的文件系统用于稳固存储,在X65中,包括默认可见的0:和1:、2:,使用数字而不是以前的ABC来作为盘符。其中0是用户可见的系统,1好像是缓存,2是系统文件。西门子使用文件来存储一部分系统信息,包括加载的铃声和机身短消息等,而不是之前的完全存储在EEP中。
下面说道作X65Patcher的装备了。
硬件:一台电脑,屏幕尽量大,液晶最好(在长时间看反汇编时就会知道好处了!)
可选:X65系列手机一台,可刷机的数据线一条(USB或COM)
软件:IDA Pro 4.7(其他支持的版本亦可,ADS1.2(推荐)或其他ARM编译环境,sfe或Smelter
可选:V_KLay X65Flasher 以及其他若干小工具
作Patcher的第一步就是得到手机的FullFlash了,这里说的FullFlash指的是手机Flash的完整映像,如果可能的话有RAM的映像是最理想的了,可以看到一些运行期数据,不过这个需要再开机运行时用AT指令或其他方式获得。具体可以用V_KLay从本机得到,也可以在网上下载别人的版本,但最好是干净的FullFlash,就是没有Patch过的版本。下面我们谈到的FullFlash是指32M的Flash部分。西门子把Flash芯片的内容映射到A0000000的部分,而把Ram映射到A8000000,所以,为了正确的反汇编指令的寻址,我们在IDA中也要作相应的设置,具体的步骤如下:
1、启动IDA,打开你的FullFlash文件,在这里你可以选择处理器和一些选项,我们选择最上面一项ARM Processor:ARM,后面的ARMB指的是ARM的BIG-ENDIAN,默认的是Little-Endian,就是和X86一样的字节序:低位在前,高位灾后。不需改变别的选项,选择确定,在弹出的是否切换处理器中选择是
UploadFile/2005-3/2005316181813859.jpg

2、设定FullFlash的映射方式,这里面我们要设定映射的地址,如图:然后是一段时间的分析过程
UploadFile/2005-3/2005316181821903.jpg
3、基本的分析完成后会如下面的情况,因为是FullFlash的映像,IDA并不像PE文件那样,知道具体的程序结构,比如那些是指令,那些是数据。基本分析完成后,只能扫描得到字符串。
UploadFile/2005-3/2005316181831152.jpg
4、再作了一些细微的调整后(包括界面),如下模样。在这里它能显示出特定的代码,比如THUMB指令,是因为我手动指定的。在IDA里面,可以用C指令强制转换为代码,D是数据,A是字符串,此外可以从菜单中更详细的指定。比如什么样的字符串,或者WORD还是DWORD等。需要注意的是切换ARM和THUMB指令,在IDA里面可以设置特定处理器的寄存器,比如ARM的T寄存器,方法是ALT+G,在出现的对话框里面设定T为1就是THUMB指令,0则是ARM,此外IDA有相当多的快捷方式,比如N为命名,ALT+R为指定基地址等(在C166中很有用)。
UploadFile/2005-3/2005316181843223.jpg
至此,基本工作完成了,我们剩下的主要工作就是阅读反汇编的部分了。
我们前面说过ARM是32位的处理器,有32位的数据总线,所以,一般情况x65里面的数据都是4字节对齐的,也就是说大多使用DWORD,这样的好处是可以带来更高的总线效率。对于Patcher来说,我们最常接触的资源就是图片、字串。我们先说一下字符串的格式,西门子在内部使用两种格式的字符串,一种是MultiBytes的,一种是UNICODE UTF16的。对于前一种字符来说,是兼容ASCII码的,其他字符集的字符是使用一种特别的编码方式,而且可以使用前导字符来指明后面所属的字符集,比如91是确省的字符集,95是English的字符集,而93h是指向一些内部的小图片。具体我就不说了,因为在SPGC组里可以找到很方便的工具来转换这些。而对于后者(UNICODE)来说,一般使用一种我称之为WString的结构来使用的,他的基本数据结构如下

Struct WString{
WORD * pBuf;
int buflen;
}

而在pBuf中,第一个字是此字符串的长度。其中buflen值得是pBuf的字长度,而不是字节长度。
在手机内部,有相当多的函数来为之服务,而对于第一种MultiBytes的字符串来说,是兼容C的字符串的,所以由C的库函数来为之服务。在手机内部有一个函数我称之谓SieStrToWString的函数来实现转换,但是对于反向转换的函数我还没找到。此外,要说一下语言包,西门子的语言包在Lg1种是一种可加载的资源,也就是说它是相对定位且自描绘的,语言包的详细结构因为过于复杂我也不说了,但这个也可以从SPGC里面找到,大体上是一种Hash索引,高频字压缩的结构,里面可以容纳多个语言的字串包。他里面的字符和前面提到的两种字符都是不同的,经过自己的独特处理的。对于语言包里的字符串,系统是通过ID来索引的,这个ID和windows里面的资源ID类似,系统提供了ID2WString函数来得到ID所对应的字符串,颇像MFC中的CString::LoadString。系统在一些界面相关的地方,大量使用了字串ID。比如左右软键,一些界面出现的文字,一些弹出菜单的文字等。这样的最大好处就是对于国际化是非常简单的,因为西门子的手机是在国际销售的,如果你深入阅读下去,可以发现西门子的手机软件是非常工程化的,体系持续,内部分层非常细,具有很强的生命力,但也正因为如此,显得过分复杂,以致于在执行速度上受到了影响。除了语言包的字串外,系统还提供了一些其他字串,其中大于0x1D9B的字串是固定在系统中的,一般是一些英文的字串还有特殊的字串。其中网络服务商的名字就是在这里面。此外,还可以使用自定义字串ID,在X65上是大于0x2710小于0x7FFF的ID(以上数字基于CX6CV25),这些ID可以用来自定义字串,系统有如下的函数StoreWStringToStringID和ReleaseStringID为之服务,用来存储自定义字串到特定的ID,这些ID可以和语言包ID一样使用。

下面说一下图片,在西门子内部使用的图片资源也是基于ID的,其实这一点和Windows处理资源的方式很像,有一个图片的索引表(可能不止一个),在SPGC中称之为PIT的结构,Picture Index Table,其中每一个Index的结构如下:

struct PicIndex{
    BYTE width;
    BYTE Hight;
    WORD Flag;
    BYTE *pBytes;
};

其中Flag字段指名图片的的色彩位数还有是否压缩。我的初步了解是bit7标明是否是压缩的图片。bit0-bit6指名位数,具体对应是:1-单色、3-2色、5-8位色、7-12位色、8-16位色。16位色是目前内置图片支持的最高位数。压缩的算法我没有研究过,应该是把具有相同色彩值的像素点进行压缩,因为大量的图片都是色彩变化比较平缓的,有很大的压缩率。系统用于显示图片一般是调用一个我称之为DrawImageByID的函数,原形是
DrawImageByID(int x, int y, int ID)
,还有一个函数用来根据一个PicIndex结构来显示图片,大概得原型是
DrawImageByHead(int x, int y, int width, int hight, PicIndex * pHead)
。外还有一些特殊的图片,一般是4Exx的ID。
      铃声和图片一样,内置铃声资源都是基于ID的,有类似的RIT结构,感兴趣的可以用smelter来研究一下这种结构。
此外,还有EEP,这说不上是一种资源,只能说是一种存储数据的结构,不仅是EEP,还有文件系统,也就是通常意义上的动态内存(一个名不副实的词,不知谁起的,可能是来自于FlexMEM)。以及一些其他存储单元(EXIT,BCORE,__FM__)都是使用统一的存储结构,大体上是在Flash的特定区域,以基于Block的方式存储数据。其中Block有自己的索引表,一般是在区域的底部。前面有一个头信息。比如经常说的电参,就是EEP中的一个Block67。而文件系统,内部称之为FFS、FFS_B和FFS_C的单元,分别对应于0、1、2三存储分区。西门子的文件系统中使用了FAT16的存储格式,在FFS中,每个Block的大小是200h,即512字节,也就是模拟了磁盘的一个扇区,然后在此基础上,建立一个MS-DOS的FAT16的文件系统。通常EEP有点特殊的是EEP所在的区域有较小的Flash擦除单位。
还有一种特殊的结构,就是菜单,其实菜单并不是是如上的资源,而是特定的窗体使用的结构,一般是列表式的菜单。因为结构固定,所以可以搜索Flash来查找这种结构的实例。他的基本结构如下:

struct MenuItem{
    DWORD *IconList;
    DWORD NormalFontID;
    DWORD BigFontID;
    DWORD unKnown;
    struct SoftKeyInfo* SoftKeyAbout;
    DWORD unKnownq;
    DWORD Flag;
}

其中NormalFontID和BigFontID是出于正常字体和大字体时的字串ID,区别是某些时候大字体时字串中要增加换行。IconList一般是图片前面的图标的列表。而SoftKeyAbout是用来定义当光标在此项时软键的定义信息,这个以后再讲。最后一个Flag标志很重要,系统会根据这个标志来决定是否显示某些菜单项。当然这个Flag相当于一个参数索引,系统将之传入一个类似
bool GetSystemParam(DWORD flag)
的函数来获得一个bool值,并由此决定是否显示。而这些参数通常来自于EEP的某些Block。
下面我们说一下ARM系统上的过程调用规则,即APCS(ARM Procedure Call Standard)。APCS 定义了:
对寄存器使用的限制。
使用栈的惯例。
在函数调用之间传递/返回参数。
可以被‘回溯’的基于栈的结构的格式,用来提供从失败点到程序入口的函数(和给予的参数)的列表。
对于第四条,因为我本身也不太懂,那么就主要说一下前面的几个。
1、对寄存器的使用限制。如下:

寄存器名字
Reg #APCS   意义
R0 a1 工作寄存器
R1 a2 "
R2 a3 "
R3 a4 "
R4 v1 必须保护
R5 v2 "
R6 v3 "
R7 v4 "
R8 v5 "
R9 v6 "
R10 sl 栈限制
R11 fp 桢指针
R12 ip
R13 sp 栈指针
R14 lr 连接寄存器
R15 pc 程序计数器
这16个寄存器是我们最常使用的,而在THUMB模式下,我们只可以访问R0-R7,对R8-R15的访问受到一定的限制。
在我们查看刚进入函数的时候:
pc 总是包含下一个要被执行的指令的位置。
lr (总是)包含着退出时要装载到 pc 中的值。在 26-bit 位代码中它还包含着 PSR。
sp 指向当前的栈块(chunk)限制,或它的上面。这是用于复制临时数据、寄存器和类似的东西到其中的地方。在 RISC OS 下,你有可选择的至少 256 字节来扩展它。
fp 要么是零,要么指向回溯结构的最当前的部分。
函数实参布置成(下面)描述的那样。
 
实际参数
前 4 个整数实参(或者更少!)被装载到 a1 - a4。
前 4 个浮点实参(或者更少!)被装载到 f0 - f3。
其他任何实参(如果有的话)存储在内存中,用进入函数时紧接在 sp 的值上面的字来指向。换句话说,其余的参数被压入栈顶。所以要想简单。最好定义接受 4 个或更少的参数的函数。
 
函数退出
通过把返回连接值传送到程序计数器中来退出函数,并且:
如果函数返回一个小于等于一个字大小的值,则把这个值放置到 a1 中。a2、a3和a4也可以用来返回值
如果函数返回一个浮点值,则把它放入 f0 中。
sp、fp、sl、v1-v6、和 f4-f7 应当被恢复(如果被改动了)为包含在进入函数时它所持有的值。
ip、lr、a2-a4、f1-f3 和入栈的这些实参可以被破坏。
以上内容来自《ARM 指令集》。
此外,需要重点说一下ARM的跳转指令,也成为分支指令(Branch),这个是ARM中比较复杂的东西,对于跳转指令来说,主要有B、BL。而根据在ARM和Thumb之间切换,又有BLX,BX。B就是一个直接跳转,而BL是带连接的跳转,所谓带连接,就是把PC寄存器中的内容放入LR寄存器,这样在跳转之后,可以通过把LR中的地址放入PC来返回跳转的地方,类似于CALL指令,不同的是BL仅仅记录了返回地址,而需要你自己来返回。ARM中B和BL的跳转偏移是+-32M,THUMB中的B跳转偏移是+-256bytes,BL是+—4M。BX和BLX是可以切换T状态寄存器的。其中的切换又根据ARM或THUMB指令集而有各自的规定,非常复杂,大家可以看处理器手册,说得比我清楚。我们比较常用的BLX的操作数是寄存器的版本,此时寄存器内的bit0决定了T寄存器。也是常用的在32位空间内调用函数的方法。
那么,所谓Patch,无甚神奇,不过是在特定的时间,出现在特定的地点,作特定的事。而在特定的地点,通常有固有的行为,我们要做的就是改变固有行为,如果此地能容得下我们的行为,比如仅仅修改一个跳转地址,那么就在原地修改。而通常的情况是,我们要做一些更复杂的行为,这时,要在另外的位置来书写我们的行为,而对于原地址来说,就是一个跳转的过程,至于是不是返回,就另当别论。从上面,我们可以看出,在ARM中作跳转的主要办法是:1、用分支指令,2、修改PC寄存器。而在西门子的系统中,除了一些对性能有要求的部分以外,大量使用了THUMB指令。那么我们知道简单的修改BL指令(4个字节)只能跳转到4M以内,如果想整个Flash内跳转,至少要8个字节。而对于ARM指令内要简单一些。通常的模式是在需要Patch的地方(通常是THUMB指令)替换某些指令产生一个BL指令,跳转到我们的主程序,而主程序通常放在4M以内的一个空白空间里。然后再完成自己的动作后,用如下指令

   MOV PC, LR



   LDR R0, =ReturnAddress
   MOV PC, R0

来返回跳转点或其他位置。对于第一种情况,前提是你在自己的动作里没有修改LR,如果有这种行为,比如用BL调用了另一个函数,就需要你自己保存LR,常用的可以压在栈里。如:

   PUSH    {LR}
   POP {PC}

对于一些使用函数指针,即函数地址的地方,则可以直接修改这个地址来达到替换原有功能的的目的,比如菜单项的响应函数。
[此贴子已经被作者于2005-3-31 8:39:24编辑过]

Bennie 发表于 2005-8-14 00:01:00

待续……可能说一些西门子软件的基本结构,包括重复C166时代的部分的一些资源格式和函数形式,此外还有ARM时代的独特东西,比如在ARM中怎么寻找地址调用,怎么处理跳转,怎么做函数调用Hook,在ARM和Thumb指令间调用等,以及ADS的使用。

qtazure 发表于 2005-8-14 00:03:00

呵呵期待你的后续……

lijingwei 发表于 2005-8-14 00:04:00

才看到呢,,,强烈期待

woodylic 发表于 2005-8-14 00:05:00

收藏学习

regspy 发表于 2005-8-14 00:06:00

期待……

realfox 发表于 2005-8-14 00:07:00

bennie更新了,顶一下,大家看看

moriya 发表于 2005-8-14 00:08:00

学习

长公子威 发表于 2005-8-14 00:09:00

加bennie为贵宾!

aaqaaq 发表于 2005-8-14 00:10:00

期待

舞上天 发表于 2005-8-14 00:11:00

期待中…………………………………………

xnjatvj 发表于 2005-8-14 00:12:00

精华!!!!!!!!!!!!有点蒙,没基础!!!!!!!!!!!!!

fsclub 发表于 2005-8-14 00:13:00

占位先.现在一起在用ICCAVR研究AVR的编程,由于没有ARM9XX的单片机,也没有基于ARM9的手机,现在还没有条件搞ARM.不过要是谁能够用C平台来开发补丁的话,我想效率会高很多(当然可能绝对定位地址困难一些).

tangxjcxv65 发表于 2005-8-14 00:14:00

图片更新

能否将这些图片更新一下:
UploadFile/2005-3/2005316181813859.jpg
UploadFile/2005-3/2005316181821903.jpg
UploadFile/2005-3/2005316181831152.jpg
UploadFile/2005-3/2005316181843223.jpg
或发到 : txiaojun@163.com
谢过了!

Ocean 发表于 2005-8-14 00:15:00

虽然不能完全理解,还是读完了。期待续篇

devil_997 发表于 2005-8-14 00:16:00

看来我是不行的了...
我一看到汇编就头痛...
只好..看各位老大发挥了..

懒笨笨 发表于 2005-8-14 00:17:00

原帖由 devil_997 于 2005-6-7 20:42 发表
看来我是不行的了...
我一看到汇编就头痛...
只好..看各位老大发挥了..


呵呵,我连汇编是什么都不知道,只知道顶!!!!!!!!!

洗心 发表于 2005-8-14 00:18:00

会顶就行了啊:) 不过,各位高手们,有没有哪位愿意牺牲一点时间写一篇浅显易懂的入门文章,也让我们这些什么也不懂的菜鸟们学习一下啊?

lisugar 发表于 2005-8-14 00:19:00

真的很不错,期待着下文

BTW
请问文中提到的StoreWStringToStringID和ReleaseStringID这两个函数的入口在哪里?怎么能找到

suede406 发表于 2005-9-9 01:03:29

这就是学问啊
顶你
页: [1] 2
查看完整版本: 【Patch相关】西门子X65系列Patch教程