上周搞了一个flexLM的程序, 打算发破解笔记的时候, 抓软件新版发现Lz0放了一个注册机, 还是开源的.
所以岁末第一篇只好改这个了.
话说从Windows3.1开始我就对Windows的取色框欲求不满了, 曾经热切盼望2000和XP的取色框有所改观, 到了Windows 2008的时候我终于彻底失望了.
这个取色框的缺点就不用我一一说了吧, 很多软件里面, 提供自己的选色功能外, 都会提供自由选色功能, 绝大多数小软件都会乖乖的使用系统的这个取色框, 一个如时间机器般的莫名其妙的存在.
首先不能输入十六进色值就可以毙了他了, 更不要说只有HSB模式而且只是其中B柱条一种了, 而且这个模式下面取色区的显示还有bug.
终于某一年, 心存不满的我看到了当时很绚的Whistler并且失望后, 无意中装了一个Photoshop(做网页用).
当然看到鸟可耻的photoshop的取色框, 而且开始暗暗期待M$把取色框改这样了.
花开两陀, 各表一枝. 后来随着俺开始做软件, 也要用到取色功能, 自然为了向Adobe致敬, 俺克隆了一个92%相似度的取色框.
又后来, 随着俺发现LordPE等工具可以添加导入表, 也就开始将其制成一个dll, 提供和系统取色框相同的接口, 用来替换使用了系统对话取色框的程序.
这么平安无事的过了几年, 除了vista和2008带来的失望外, 我只是偶尔在群里面上抱怨一下. 直到某天世纪的群里面有人说看雪坛子上有个M$安全聚会, 问俺要不要去演示改造取色框的故事, 这么着俺就造了一个话题, 蹭了一个名额去了.
其实之前我也有分享我的修改, 只不过多半是给做设计的朋友. 因为Fireworks, Dreamweaver等软件除了在固定的色票选取以外, 要自由选色, 也会跟其他小公司软件一样无畏地弹出系统的取色框, 毫不悔改, 毫不以为耻. 有鸟Adobe的取色框后, 这些一蹶不振的软件配起色来又重新焕发鸟青春, 代价就是俺每次都要拿到软件都要修改一遍, 还有就是还给别人的时候, 多了一个libpicker.dll .
这里先声明一句, 此对话框完全不包括Adobe公司任何源代码, (这也要得搞得到啊).
那次的话题就是将系统的comdlg32.dll里面提供的取色框功能替代成自己的. 取代和改变系统API的功能, 俺用过的有若干方法,
其一, 各种全局挂钩的方式, 这或许是最无聊的办法了吧, 连普通用户都晓得这么干, 多半是流氓软件普及的结果吧.
比较洁净点的, 在程序目录放置空壳comdlg32.dll, 其他函数全部指向system32目录下的comdlg32, 仅仅实现ChooseColorW的功能. (这办法是宇宙杰出青年告诉的, 不过用户看到后还是觉得郁闷吧. )
其三, 在系统的comdlg32.dll里面插入libpicker.dll的导入项, 然后修改ChooseColorW的入口, 调用新的取色框. 这个跟前面的修改需要美化的程序没有大的区别, 同样会在系统目录留下把柄, 被人指摘.
厄, 果然最后就是比较绿色的办法, 跟系统dll进行合体, 溶解在comdlg32.dll的体内, 无声无息, 今天要表的段子就是这段大和谐了.
因为播出规制的原因, 先用一个非系统dll, MFC42u.dll来做演示, 好吧我马上承认了其实是上次的话题就是这个比较跟M$没有关系的MFC的运行库, comdlg32.dll的修改虽然和这个一样, 但是俺没有写笔记, 预计留给明年的自动修改工具发布贴了~~
选这个dll是因为开始打算做一个合并取色框dll到exe的演示作为话题的第一部分, 结果发现这个exe本身没有调用Win32 API, 是使用MFC的dll的功能, 就拿来作dll互相百合的例子了.
各位请看这个MFC42u.dll
我打算将libpicker的段拆出来, 合并到MFC42u.dll里面, Libpicker的text插入到.data结尾的107000处, 资源段和重定位段进行合并, 放在两者的后面.
当然俺的dll的第一个段起始RVA并不是7D307000, 这本身没法是个合法的基址, 有看官可能要说了, 设置链接器属性可以将基址和首段的起始位置结合起来得到7D307000, 那前提是要合并的dll是我写得, 很多情况只是凑巧了.
不过dll身为女儿身, 最美妙的地方是带了一个重定位表, 根据这个东西我们完全可以把dll里面的段都给重定位到完全不合理的地址去.
原MFC的载入基址是7D200000,
(7D200000+107000) - (400000+1000) = 7CF06000
俺打开Rejacker, 使用固态重定位功能将文件重定位这个不伦不类的地址, 并且将CODE,DATA,BSS几个段合并到原dll中.
然后两个dll里面的各种非代码部分的段和表需要合并, 计有资源表, 导入表, 重定位表, 而libpicker的导出表就不需要了, 内部消化了.
在以前合并exe/dll时候, 我通常会用Rejacker导出原始程序的重定位表, 其中要合并入受方的模块使用表地址重定位功能导出, 然后粘贴在一起, 用ImpRec直接重建一个新的, 不过在这个MFC的dll面前, ImpRec倒下了, 重建后的dll完全不能载入.
那好吧我只能重建Descriptor来干了. 2个模块都各有10个描述项(10个导入的dll), 合并在一起就是10*20+10*20 = 21*20 = 420字节.
如果用手来量就是C8(@F2598) + C8(@17200) + 14(结束) = 1A4, 尺寸是一样的.
粘贴下来后, 后面的C8里面修正一下抠过来后导致的偏差, 106000(107000-1000?), 这个可以用010的批量计算完成的.
每个记录中的最后的0190DC倒不需要修正.
然后找到内部使用ChooseColorW的地方, 修改为调用自身的
7D31BD68(合并后的libpicker新取色框功能)
7D24A471 . 50 PUSH EAX ; /pChooseColor 7D24A472 . FF15 A817307D CALL NEAR DWORD PTR DS:[7D3017A8] ; \ChooseColorW
最后一步需要人工操作的貌似只有合并OEP了吧, 在dll被调用的时候, 先后初始化两个dll, 其中任何一个dll失败就返回失败.
写了一段代码, 用skypatch打到留出的空隙处.
push ebp
mov ebp,esp
push ebx
push esi
push edi
mov ebx, [ebp+10] // lpReserved
mov esi, [ebp+C] // fdwReason
mov edi, [ebp+8] // hinstDLL
push ebx
push esi
push edi
call mfcoep
push eax
push ebx
push esi
push edi
call pickeroep
pop ebx
and eax, ebx
and eax,1
pop edx
pop edi
pop esi
pop ebx
leave
retn 0c
7D31FF30 >/$ 55 PUSH EBP 7D31FF31 |. 8BEC MOV EBP, ESP 7D31FF33 |. 53 PUSH EBX 7D31FF34 |. 56 PUSH ESI 7D31FF35 |. 57 PUSH EDI 7D31FF36 |. 8B5D 10 MOV EBX, DWORD PTR [EBP+10] 7D31FF39 |. 8B75 0C MOV ESI, DWORD PTR [EBP+C] 7D31FF3C |. 8B7D 08 MOV EDI, DWORD PTR [EBP+8] 7D31FF3F |. 53 PUSH EBX ; /pReserved 7D31FF40 |. 56 PUSH ESI ; |CallReason 7D31FF41 |. 57 PUSH EDI ; |hDLLInstance 7D31FF42 |. E8 8A54FBFF CALL <mfcoep> ; \Assumed DllEntryPoint 7D31FF47 |. 50 PUSH EAX 7D31FF48 |. 53 PUSH EBX ; /pReserved 7D31FF49 |. 56 PUSH ESI ; |CallReason 7D31FF4A |. 57 PUSH EDI ; |hDLLInstance 7D31FF4B |. E8 2CC0FFFF CALL <pickeroep> ; \Assumed DllEntryPoint 7D31FF50 |. 5B POP EBX 7D31FF51 |. 21D8 AND EAX, EBX 7D31FF53 |. 83E0 01 AND EAX, 1 7D31FF56 |. 5F POP EDI 7D31FF57 |. 5E POP ESI 7D31FF58 |. 5B POP EBX 7D31FF59 |. C9 LEAVE 7D31FF5A \. C2 0C00 RETN 0C
LibPicker的重定位表是使用重定位重定位表导出功能导出的, 格式跟relox等工具兼容.
od跑了一下合体后的, 爆在tlsalloc, call [tlsalloc]里面存放的地址并没有在载入时候被PE Loader给填成新的.
回过神看了下原来这个MFC42u.dll是做过bind的, OrginalFirstThunk填PIMAGE_THUNK_DATA_NAMED名称, FirstThunk填写IAT首地址.
而不使用bind的程序的每个导入项, 导入前FirstThunk填PIMAGE_THUNK_DATA_NAMED, 导入后该处被占用为IAT.
需要2倍大小的Picker的IAT作为新的OrginalFirstThunk的存放处, 原充当名称的FirstThunk安心充当IAT.
于是开出$288的大小来存放OrginalFirstThunk.
并且将OrginalFirstThunk的值设置为FirstThunk+E84 (11FF60-11F0DC)
Kernel32, OrginalFirstThunk 11FF60, FirstThunk 11F0DC
这里我不禁要赞美一下010Editor, 对于这种临时处理, 完全不用自己写工具或者脚本, 给出操作类型的长度, 给出跳过的大小(结构大小-操作数据长度), 一下就批量完毕了, 嗷嗷嗷.
这个对话框的意思就是
for I := 0 to Length(Descriptor) - 1 do begin INC(Descriptor[I].OrginalfirstThunk, $E84); end;
加工后的dll还被我扩大了Bound Import所在的头部, 然后用bind加工, 无事的平淡启动了.
点击选色后, 按照约定弹出了新的取色框.
合并后的导入表:
合并后的资源:
合并后的Bound Import:
最后全家福, MFC和KOL(一套API浅封装库)的无畏合体啊
"test" / \ <