我们接下去看怎么手工替换公钥,又怎样用程序实现自动替换。
(a)FlexLM SDK v9.2 ECC公钥替换
再回头看看v9.2版本SDK编译产生的testlmd.exe里第一个出现的5D怎么来的。
00403C0A |. 0305 30775200 ADD EAX,DWORD PTR DS:[527730]
00403C10 |. 8B4D 0C MOV ECX,DWORD PTR SS:[EBP+C]
00403C13 |. 8881 AA000000 MOV BYTE PTR DS:[ECX+AA],AL
第一个pubkey的值出现的是在.text:403C0A,然后在.text:00403C13往内存0012F196处写5D
插入图
看下信息窗口里的内容
AL=5D (']')
堆栈 DS:[0012F196]=00
ECX的值是0012F0EC,
所以内存[0012F184 - 0012F1A2]分别对应
[ECX + 98h] => 十进制 [ecx + 152]
......
[ECX + B6h] => 十进制 [ecx + 182]
请注意理解这里的(152 ~ 182),后面的不同的SDK版本的ECC pubkey替换仍然要用到这个方法。
我们把sub_401E60 (即_l_n36_buf)F5转伪代码截取memset开始到末尾的一段(见附件ida_f5.txt)
从中很容易(可以用编程脚本提取)出pubkey存储的位置。
*((_BYTE *)Dst + 152) += dword_526E30; => 526E30存放76
*((_BYTE *)Dst + 153) += dword_527D1C; => 527D1C存放9d
*((_BYTE *)Dst + 154) += dword_527634; => 527634存放e2
*((_BYTE *)Dst + 155) += dword_5275C8; => 5275C8存放ab
*((_BYTE *)Dst + 156) += dword_527EA4; => 527EA4存放3b
*((_BYTE *)Dst + 157) += dword_527824; => 527824存放42
*((_BYTE *)Dst + 158) += dword_527344; => 527344存放d7
*((_BYTE *)Dst + 159) += dword_527AD4; => 527AD4存放6b
*((_BYTE *)Dst + 160) += dword_526E7C; => 526E7C存放20
*((_BYTE *)Dst + 161) += dword_5277B8; => 5277B8存放b5
*((_BYTE *)Dst + 162) += dword_527864; => 527864存放46
*((_BYTE *)Dst + 163) += dword_527314; => 527314存放39
*((_BYTE *)Dst + 164) += dword_527624; => 527624存放ed
*((_BYTE *)Dst + 165) += dword_527DF4; => 527DF4存放bc
*((_BYTE *)Dst + 166) += dword_52707C; => 52707C存放a0
*((_BYTE *)Dst + 167) += dword_527A8C; => 527A8C存放d1
*((_BYTE *)Dst + 168) += dword_5277C4; => 5277C4存放cb
*((_BYTE *)Dst + 169) += dword_526E1C; => 526E1C存放0b
*((_BYTE *)Dst + 170) += dword_527730; => 527730存放5d
*((_BYTE *)Dst + 171) += dword_5274B0; => 5274B0存放65
*((_BYTE *)Dst + 172) += dword_527180; => 527180存放dc
*((_BYTE *)Dst + 173) += dword_5278E4; => 5278E4存放e5
*((_BYTE *)Dst + 174) += dword_527178; => 527178存放39
*((_BYTE *)Dst + 175) += dword_527540; => 527540存放63
*((_BYTE *)Dst + 176) += dword_527AC8; => 527AC8存放44
*((_BYTE *)Dst + 177) += dword_52766C; => 52766C存放80
*((_BYTE *)Dst + 178) += dword_527A54; => 527A54存放cd
*((_BYTE *)Dst + 179) += dword_527070; => 527070存放78
*((_BYTE *)Dst + 180) += dword_527140; => 527140存放27
*((_BYTE *)Dst + 181) += dword_5278F4; => 5278F4存放8c
*((_BYTE *)Dst + 182) += dword_5270F0; => 5270F0存放17
请注意上面的(152,153......182)的排序,IDA F5的输出不是这样的,这里排好序是为了后面脚本处理时,原pubkey和要替换的pubkey比较容易一一对应上。
但是替换时,必须要按地址存放顺序搜索、替换,呵呵这个稍微想一下,应该不难理解。
这样排序后,原来的pubkey和将要替换的pubkey就很容易一一对应上了
org_pubkey = '76 9d e2 ab 3b 42 d7 6b 20 b5 46 39 ed bc a0 d1 cb 0b 5d 65 dc e5 39 63 44 80 cd 78 27 8c 17'
rep_pubkey = '76 e5 b4 61 32 35 26 f4 6d 28 d8 28 c4 8d 4c 73 bb dc fe 5f 0f 90 ad 24 97 83 0b 0c 47 e5 ff'
手工替换,就找到相应的地址,手工输入替换就可以了。
至于自动替换,这里是用ruby脚本实现的。
在编程脚本里很容易再按地址排序,并将org_pubkey和rep_pubkey随之相应按地址一一对应如下
526E1C 0b dc
526E30 76 76
526E7C 20 6d
527070 78 0c
52707C a0 4c
5270F0 17 ff
527140 27 47
527178 39 ad
527180 dc 0f
527314 39 28
527344 d7 26
5274B0 65 5f
527540 63 24
5275C8 ab 61
527624 ed c4
527634 e2 b4
52766C 80 83
527730 5d fe
5277B8 b5 28
5277C4 cb bb
527824 42 35
527864 46 d8
5278E4 e5 90
5278F4 8c e5
527A54 cd 0b
527A8C d1 73
527AC8 44 97
527AD4 6b f4
527D1C 9d e5
527DF4 bc 8d
527EA4 3b 32
这时就可以搜索、替换了,整个的搜索、替换的规律如下
0b......76......20...... ......9d......bc......3b
=>
dc......76......6d...... ......e5......8d......32
由于数据不是连续存放的,中间“......”对应的数据必须原封不动的保留。
你可以将脚本里得到的total_search输出
total_search = total_search(address, save)
0b(.{38})76(.{150})20(.{998})78(.{22})a0(.{230})17(.{158})27(.{110})39(.{14})dc(.{806})39(.{94})d7(.{726})65(.{286})63(.{270})ab(.{182})ed(.{30})e2(.{110})80(.{390})5d(.{270})b5(.{22})cb(.{190})42(.{126})46(.{254})e5(.{30})8c(.{702})cd(.{110})d1(.{118})44(.{22})6b(.{1166})9d(.{430})bc(.{350})3b
(.{38}) => 0b和76间有38个其他数字,这里38是程序根据0b和76的存放地址的差(526E30 - 526E1C)自动计算出来的
作为参考,公钥替换脚本见附件
testlmd_replace_pubkey_v9.2.rb ,是一个ruby脚本,可以用testlmd_replace_pubkey_v9.2.rb ida_f5.txt testlmd.exe替换testlmd.exe里的公钥,输出文件为outfile。
声明:这里的脚本只是实现了功能,性能上未作优化(修改大的应用文件会很慢),仅供参考。从实用的角度而言,优化下这个脚本是可行的,如果懒得优化的话,可以从这个脚本输出seatch/replace文本,然后用sfk(Swiss File Knife)全目录自动替换。
稍后看下11.9.1和11.11.1.1的ECC公钥替换
......
上传的附件: