010Editor修改通配符为??教程
最近whyida在论坛上发了一下010Editor最新版的分析和注册机,所以我更换掉了一直使用的WinHex,准备试下010Editor,用起来果然还挺不错的,还能装插件自动识别PE头,但是010Editor里的搜索功能里通配符是用?来代替一个byte,这个和OD里的使用习惯不太一样,OD里都是用??来表示任意byte,所以我用起来总感觉有些别扭,虽然也不是什么大事:\于是就有了这篇改造010Editor的教程,修改后用??来表示搜索任意byte,如果剩下单数个的?,也会被视作??,比如?FE和??FE都是表示OD里的搜索??FE,???FE和????FE就都表示OD里的????FE
[开始改造]
010Editor在没搜到东西的时候会提示No occurrences of xxx,所以我们搜索ASCII字符串no occurrences,结果如下:
Ultra String Reference Plugin, item 5484
Address=008926FE
Disassembly=PUSH 010Edito.0196E63C
Text String=no occurrences of '
到 008926FE 这里以后一直拉到段首下断,也就是如下位置
00892330 > \55 PUSH EBP
段首不远处就能看到如下调用
008923A3 .FF15 2C8D6C02 CALL DWORD PTR DS:[<&Qt5Widgets.QLineEdit::text>] ;Qt5Widge.QLineEdit::text
这个肯定就是取我们输入的search string了,过这个call以后查看eax会发现确实如此
我们如果要修改使用??来搜索?,一个简单的方法就是把008923A3这行代码返回的QString做一个替换,将??替换为?,因为程序里的原本的搜索功能是用?来搜索一个byte的
右键Qt5Core.dll->详细信息里可以看到使用的Qt版本是5.410,所以我们可以去QT的官网下载一个5.410的环境,写一个replace的函数,编译以后把代码挪过来(或者写成DLL调用也可以),编译好后的replace的函数长这样子:
004019A0/$6A FF PUSH -0x1
004019A2|.68 B22D4000 PUSH QtTest.00402DB2
004019A7|.64:A1 0000000>MOV EAX, DWORD PTR FS:
004019AD|.50 PUSH EAX
004019AE|.83EC 08 SUB ESP, 0x8
004019B1|.56 PUSH ESI
004019B2|.A1 24704000 MOV EAX, DWORD PTR DS:
004019B7|.33C4 XOR EAX, ESP
004019B9|.50 PUSH EAX
004019BA|.8D4424 10 LEA EAX, DWORD PTR SS:
004019BE|.64:A3 0000000>MOV DWORD PTR FS:, EAX
004019C4|.6A FF PUSH -0x1
004019C6|.8D4424 10 LEA EAX, DWORD PTR SS:
004019CA|.68 6C3A4000 PUSH QtTest.00403A6C ;ASCII "?"
004019CF|.50 PUSH EAX
004019D0|.FF15 10314000 CALL DWORD PTR DS:[<&Qt5Core.QString::fromUtf8>] ;Qt5Core.QString::fromUtf8
004019D6|.8BF0 MOV ESI, EAX
004019D8|.6A FF PUSH -0x1
004019DA|.8D4424 18 LEA EAX, DWORD PTR SS:
004019DE|.C74424 28 000>MOV DWORD PTR SS:, 0x0
004019E6|.68 703A4000 PUSH QtTest.00403A70 ;ASCII "??"
004019EB|.50 PUSH EAX
004019EC|.FF15 10314000 CALL DWORD PTR DS:[<&Qt5Core.QString::fromUtf8>] ;Qt5Core.QString::fromUtf8
004019F2|.83C4 18 ADD ESP, 0x18
004019F5|.8B4C24 20 MOV ECX, DWORD PTR SS:
004019F9|.6A 01 PUSH 0x1
004019FB|.56 PUSH ESI
004019FC|.50 PUSH EAX
004019FD|.C64424 24 01MOV BYTE PTR SS:, 0x1
00401A02|.FF15 14314000 CALL DWORD PTR DS:[<&Qt5Core.QString::replace>] ;Qt5Core.QString::replace
00401A08|.8D4C24 08 LEA ECX, DWORD PTR SS:
00401A0C|.C64424 18 00MOV BYTE PTR SS:, 0x0
00401A11|.FF15 18314000 CALL DWORD PTR DS:[<&Qt5Core.QString::~QString>] ;Qt5Core.QXmlStreamStringRef::~QXmlStreamStringRef
00401A17|.8D4C24 0C LEA ECX, DWORD PTR SS:
00401A1B|.C74424 18 FFF>MOV DWORD PTR SS:, -0x1
00401A23|.FF15 18314000 CALL DWORD PTR DS:[<&Qt5Core.QString::~QString>] ;Qt5Core.QXmlStreamStringRef::~QXmlStreamStringRef
00401A29|.8B4C24 10 MOV ECX, DWORD PTR SS:
00401A2D|.64:890D 00000>MOV DWORD PTR FS:, ECX
00401A34|.59 POP ECX
00401A35|.5E POP ESI
00401A36|.83C4 14 ADD ESP, 0x14
00401A39\.C3 RETN
这个函数我们可以自己改一下,去掉前面的SEH的,然后有些像004019FD,00401A0C,00401A1B这几行的东西好像是用来记录QT函数内部还未销毁的字符串数量的,也可以删掉
然后我们将原来获取LineEdit::text后的三行
008923A9 50 PUSH EAX
008923AA 8D4D F0 LEA ECX, DWORD PTR SS:
008923AD C645 FC 01 MOV BYTE PTR SS:, 0x1
改为
008923A9 . /E9 52F2C800 JMP 010Edito.01521600
008923AE |90 NOP
008923AF |90 NOP
008923B0 |90 NOP
01521600这里就填上我们的replace的代码
01521600 > \50 PUSH EAX
01521601 .8D4D F0 LEA ECX, DWORD PTR SS:
01521604 .C645 FC 01 MOV BYTE PTR SS:, 0x1
01521608 .60 PUSHAD
01521609 .9C PUSHFD
0152160A .83EC 08 SUB ESP, 0x8
0152160D .6A FF PUSH -0x1
0152160F .8D4424 04 LEA EAX, DWORD PTR SS:
01521613 .68 80165201 PUSH 010Edito.01521680
01521618 .50 PUSH EAX
01521619 .FF15 787C6C02 CALL DWORD PTR DS:[<&Qt5Core.QString:>;Qt5Core.QString::fromUtf8
0152161F .8BF0 MOV ESI, EAX
01521621 .6A FF PUSH -0x1
01521623 .8D4424 14 LEA EAX, DWORD PTR SS:
01521627 .68 84165201 PUSH 010Edito.01521684 ;ASCII "??"
0152162C .50 PUSH EAX
0152162D .FF15 787C6C02 CALL DWORD PTR DS:[<&Qt5Core.QString:>;Qt5Core.QString::fromUtf8
01521633 .6A 01 PUSH 0x1
01521635 .56 PUSH ESI
01521636 .50 PUSH EAX
01521637 .8D8C24 800000>LEA ECX, DWORD PTR SS:
0152163E .FF15 447A6C02 CALL DWORD PTR DS:[<&Qt5Core.QString:>;Qt5Core.QString::replace
01521644 .8D4C24 18 LEA ECX, DWORD PTR SS:
01521648 .FF15 A4746C02 CALL DWORD PTR DS:[<&Qt5Core.QString:>;Qt5Core.QXmlStreamStringRef::~QXmlStreamStringRef
0152164E .8D4C24 1C LEA ECX, DWORD PTR SS:
01521652 .FF15 A4746C02 CALL DWORD PTR DS:[<&Qt5Core.QString:>;Qt5Core.QXmlStreamStringRef::~QXmlStreamStringRef
01521658 .83C4 20 ADD ESP, 0x20
0152165B .9D POPFD
0152165C .61 POPAD
0152165D .^ E9 4F0D37FF JMP 010Edito.008923B1
其中01521680和01521684处需要手动填充一下数据如下
015216800000003F?...
0152168400003F3F??..
把修改都保存一下,第一步的改造就完成了,第二步是改掉搜索栏右侧的字符串提示,如下
右侧的?? ?? FE也应该显示为?? FE
我们先给LineEdit::text,也就是65105890下个断,然后我们在010Editor中按Ctrl+F,这个时候程序就需要读取LineEdit里的值从而去显示旁边的数据,所以我们从LineEdit::text里返回,看到如下代码
008952EA .8D45 E8 LEA EAX, DWORD PTR SS:
008952ED .50 PUSH EAX
008952EE .FF15 2C8D6C02 CALL DWORD PTR DS:[<&Qt5Widgets.QLineEdit::text>] ;Get Original text
008952F4 .8B8B E8000000 MOV ECX, DWORD PTR DS:
008952FA .6A 00 PUSH 0x0
008952FC .68 18576C02 PUSH 010Edito.026C5718
00895301 .56 PUSH ESI
00895302 .57 PUSH EDI
00895303 .FF348D 9C316B>PUSH DWORD PTR DS:
0089530A .8B4D EC MOV ECX, DWORD PTR SS:
0089530D .50 PUSH EAX
0089530E .8D45 F0 LEA EAX, DWORD PTR SS:
00895311 .C745 FC 00000>MOV DWORD PTR SS:, 0x0
00895318 .50 PUSH EAX
00895319 .E8 FBD5B6FF CALL 010Edito.00402919 ;Handle text
0089531E .8D4D E8 LEA ECX, DWORD PTR SS:
00895321 .C645 FC 02 MOV BYTE PTR SS:, 0x2
00895325 .FF15 A4746C02 CALL DWORD PTR DS:[<&Qt5Core.QString::~QString>] ;Qt5Core.QXmlStreamStringRef::~QXmlStreamStringRef
0089532B .8B4B 54 MOV ECX, DWORD PTR DS:
0089532E .8D45 F0 LEA EAX, DWORD PTR SS:
00895331 .50 PUSH EAX
00895332 .FF15 288D6C02 CALL DWORD PTR DS:[<&Qt5Widgets.QLineEdit::setText>] ;Qt5Widge.QLineEdit::setText
我们看到了关键词setText,那008952EE这行取了原文本,00895332这行setText,字符串处理肯定就是00895319这行了
我们跟进去发现是0106F27B这行处理的原文本
0106F27B E8 AA5C39FF CALL 010Edito.00404F2A ; !!!
这个函数是在逐个BYTE的读取一个数组,然后产生显示在右边的字符串
这个数组是将你原来查找的字符串换成二进制然后处理问号和星号等特殊符号,例子如下
FE 01 FE
第一个FE表示?,第二个01表示后面有1个非通配符,然后程序就读取后面的FE,由于之前有个01,这个FE不会被当做?,所以FE 01 FE表示的就是搜索?FE,同理01 FE FE就表示搜索FE?,这个数组是在0106F27B CALL 010Edito.00404F2A这行之前的0106F22A这一行被产生的
0106F22A E8 426639FF CALL 010Edito.00405871
生成右边的主要部分大致相当于以下代码
i = 0;
do
{
c = a;
if ( c == 0xFF )
{
*(_WORD *)pNewStr = 0x2A2A;
pNewStr += 2;
++i;
}
else if ( c == 0xFE )
{
*(_WORD *)pNewStr = 0x3F3F;
pNewStr += 2;
++i;
}
else
{
++i;
ctr = 0;
if ( c > 0 )
{
do
{
sprintf(pNewStr, "%02X", a);
pNewStr += 2;
if ( ctr < c - 1 )
*pNewStr++ = 0x20;
++ctr;
++i;
}
while ( ctr < c );
}
}
if ( i >= a->length )
break;
*pNewStr++ = 0x20;
}
while ( i < a->length );
我们只要加一个flag记录上一个字符是不是单数个问号就行了,如果当前字符是问号且flag==true,就跳过这次的输出,并且将flag置为false,同时在输出空格的位置判断上一个字符是不是空格,如果是的话就跳过这次的空格输出,修改后的代码如下
<0106D750>
@L00000001:
PUSH EBP
MOV EBP, ESP
PUSH -0x1
PUSH 0x15168A3
MOV EAX, DWORD PTR FS:
PUSH EAX
SUB ESP, 0x10
PUSH EBX
PUSH ESI
PUSH EDI
MOV EAX, DWORD PTR DS:
XOR EAX, EBP
PUSH EAX
LEA EAX, DWORD PTR SS:
MOV DWORD PTR FS:, EAX
MOV EBX, ECX
MOV DWORD PTR SS:, EBX
LEA ECX, DWORD PTR SS:
MOV DWORD PTR SS:, 0x0
CALL DWORD PTR DS:
CMP DWORD PTR SS:, 0x0
MOV DWORD PTR SS:, 0x1
JNZ SHORT @L00000002
MOV ESI, DWORD PTR SS:
PUSH 0x2
PUSH DWORD PTR SS:
PUSH DWORD PTR SS:
PUSH ESI
CALL 004097A5
ADD ESP, 0x10
LEA ECX, DWORD PTR SS:
MOV DWORD PTR SS:, 0x1
MOV BYTE PTR SS:, 0x0
CALL DWORD PTR DS:
MOV EAX, ESI
MOV ECX, DWORD PTR SS:
MOV DWORD PTR FS:, ECX
POP ECX
POP EDI
POP ESI
POP EBX
MOV ESP, EBP
POP EBP
RETN 0x10
@L00000002:
;------------------------------------
MOV BYTE PTR DS:, 0x0
;------------------------------------
MOV EAX, DWORD PTR DS:
LEA EAX, DWORD PTR DS:
INC EAX
PUSH EAX
CALL 013A6CD0
MOV ESI, EAX
MOV DWORD PTR SS:, EAX
XOR EDI, EDI
ADD ESP, 0x4
MOV BYTE PTR DS:, 0x0
CMP DWORD PTR DS:, EDI
JLE @L00000010
MOV ECX, DWORD PTR SS:
@L00000003:
MOVZX EAX, BYTE PTR DS:
MOV DWORD PTR SS:, EAX
CMP EAX, 0xFF
JNZ SHORT @L00000004
MOV BYTE PTR DS:, 0x0
MOV WORD PTR DS:, 0x2A2A
ADD ESI, 0x2
INC EDI
JMP SHORT @L00000008
@L00000004:
CMP EAX, 0xFE
JNZ SHORT @L00000005
;-----------------------------------
CMP BYTE PTR DS:, 0x0
NOT BYTE PTR DS:
JNESHORT @SKIP
MOV WORD PTR DS:, 0x3F3F
ADD ESI, 0x2
@SKIP:
;-----------------------------------
INC EDI
JMP SHORT @L00000008
@L00000005:
MOV BYTE PTR DS:, 0x0
INC EDI
XOR EBX, EBX
TEST EAX, EAX
JLE SHORT @L00000008
DEC EAX
MOV DWORD PTR SS:, EAX
@L00000006:
MOVZX EAX, BYTE PTR DS:
PUSH EAX
PUSH 0x1623AEC
PUSH ESI
CALL DWORD PTR DS:
ADD ESP, 0xC
ADD ESI, 0x2
CMP EBX, DWORD PTR SS:
JGE SHORT @L00000007
MOV BYTE PTR DS:, 0x20
INC ESI
@L00000007:
MOV ECX, DWORD PTR SS:
INC EBX
INC EDI
CMP EBX, DWORD PTR SS:
JL SHORT @L00000006
@L00000008:
MOV EAX, DWORD PTR SS:
CMP EDI, DWORD PTR DS:
JGE SHORT @L00000009
;------------------------------------
CMP EDI, 0
JE @ADDSPACE
CMP BYTE PTR DS:, 0x20
JE @DONTADD
@ADDSPACE:
MOV BYTE PTR DS:, 0x20
INC ESI
@DONTADD:
;------------------------------------
CMP EDI, DWORD PTR DS:
JL @L00000003
@L00000009:
MOV EAX, DWORD PTR SS:
@L00000010:
PUSH EAX
LEA ECX, DWORD PTR SS:
MOV BYTE PTR DS:, 0x0
CALL DWORD PTR DS:
PUSH DWORD PTR SS:
CALL 013A704C
MOV ECX, DWORD PTR SS:
LEA EAX, DWORD PTR SS:
ADD ESP, 0x4
PUSH EAX
CALL DWORD PTR DS:
LEA ECX, DWORD PTR SS:
MOV DWORD PTR SS:, 0x1
MOV BYTE PTR SS:, 0x0
CALL DWORD PTR DS:
MOV EAX, DWORD PTR SS:
MOV ECX, DWORD PTR SS:
MOV DWORD PTR FS:, ECX
POP ECX
POP EDI
POP ESI
POP EBX
MOV ESP, EBP
POP EBP
RETN 0x10
现在修改的部分已经都做完了,不过还没完!还需要修正程序的重定位信息,工具我放在附件里了,只有几个位置,手动修复的,就不详细说了
完工以后程序:
链接: http://pan.baidu.com/s/1o7GgQ86 密码: ytyw
错误之处感谢指正!有什么bug也可以告诉我~ 不错,这个厉害的。 青衣惆怅 发表于 2017-2-25 11:13
大婶~文章的意思是不是讲的把程序原来 查询的那个函数替换成自己写的函数。过程是先把自己写好的函数然后编 ...
这个是最完美的方案,你可以完全自己重写搜索的函数从而支持单个16进制位的搜索及?,但是我比较懒,仅仅是在调用内部的搜索函数之前给它加了一个函数,替换搜索字符串,搜索函数还是用的它的。如果直接替换搜索函数还会有个问题,取决于他的搜索函数耦合度低不低,如果他的搜索函数是写成Search(QString &pattern, QString &text)这种,你就很好替换,自己用QT写一个编译以后挪过去就好了,但是如果他的搜索函数写成Search(QString &pattern)这种,然后在函数内再去获取text,比如是调用ui->txtBox->text()获取的,那就不是很好替换了,需要你自己去拼凑 学习了思路,先编译代码再挪过来{:1_921:} 学习下,虽然看不懂。 百度盘密码是多少来着 好深奥。。 别的语言软件也可以先写一个子程序代码? 然后直接COPY过来用吗?? 无阻 发表于 2017-2-11 12:43
别的语言软件也可以先写一个子程序代码? 然后直接COPY过来用吗??
都可以吧,和写一个DLL然后调用其实没有本质的区别吧? mayl8822 发表于 2017-2-11 10:33
百度盘密码是多少来着
你得先开八门,然后再用白眼才能看得到 一般人根本看不懂啊这。。