我们打开软件的注册窗口,发现其会给定一个确定机器码,然后让我们输入用户名和序列号,我们随便输入假的序列号
点击确定后其会弹出:注册失败,请检查输入是否有误的窗口。
1. 我们先用PEID打开程序查一下壳(无壳)
2. 然后我们直接将程序载入OD分析
因为程序注册失败会弹出时注册失败的窗口
① 我先是从弹出失败窗口处下手(目的是想寻找调用弹出失败窗口的代码从而寻找关键判断),但是发现下了API断点后回溯寻找不到关键代码
② 那我们就换一条思路下个确定按钮事件断点(目的是为了寻找关键代码),但是发现点击确定按钮后断不下来。
③ 不这么花里胡哨的了直接搜索失败信息的字符串算了:“注册失败,请检查你的输入是否有误!”。(其实一般都是先搜索字符串,我只是想练一下①②这两种思路,如果我们在分析软件的时候应该先用③不行在试试①②)
3. 我们在OD中搜索字符串(右击选择中文智能搜索 ->按Ctrl + F后搜索"注册失败,请检查你的输入是否有误")
发现了“注册失败,请检查你的输入是否有误!”。
我们双击此字符串后进入关键代码处并在函数头部下断点我们,然后我们随便输入用户名(88888888)和假的序列号(23h4j8skeros9fg458)后点击确定
程序会停在此函数头部。
我们F8单步向下分析程序,到达关键判断处。其在调用完call 0x4135A4后(返回值为eax)
发现如果eax的值小于50则会弹出注册失败的窗口。
我们在call 004135A4处下断点,然后我们运行程序F7进入此call后进行分析。
其是先判断 0x0019E7B8地址处的值是否为0,如果为0则返回eax为0,否则返回 eax = [ [ 0x0019e7b8 ] ] - 4
我们在堆栈窗口中搜索0x19e7b8,发现其值为一个字符串的地址。(0x19e7b8应该是一个指针变量)
eax返回值[ [0x19e7b8] ]- 4 等于8 ( 正好为此字符串的长度8),我们需要知道此字符串是怎么产生的。
我们重新运行程序F8往下分析发现此字符串生成的关键算法。即把我们输入的序列号中的数字提取成此字符串且数字的个数最多为0x400个。
因为此字符串的长度为关键判断函数的返回值eax,所以我们输入的序列号中的数字的个数不能小于50。(小于50就会弹出注册失败窗口)
然后我们运行程序,更改我们输入的序列号为“12345678912345678912345678912345678912345678912345”(50个数字)点击确定后运行到跳转处。
其会执行跳转不会弹出注册失败窗口,我们F8继续往下分析
我们F8继续往下执行有到达关键跳转处,当[ebp - 0xd8] != [ebp - 0xc0]时会弹出注册失败窗口,
而[ebp - 0xd8] 和 [ebp - 0xc0]这两个值分别是函数call 0x00492000 的返回值的后16位 和 函数call 0x005d5b80的返回值
(第一个函数的返回值后16位为0x8101,第二个函数的返回值为0x3039)
我们分别进入两个函数分析其返回值生成算法,在二者调用处下断点,运行程序到第一个函数调用处F7进入函数
此函数是将序列号的前45个字符经过此算法处理后返回产生一个32位的数值然后充当返回值。
接着我们运行程序来到第二个关键函数处,F7进入此函数后我们发现当执行完call 0x005b6202后返回值eax(0x3060)已经产生,
所以此函数的eax返回值时实际是call 0x005b6202函数产生的,
我们在此函数入口处下断点运行程序来到此处后,再F7进入此函数后发现当执行完call 0x005bd528后eax返回值(0x3060)已经产生,
所以此函数的返回值是call 0x005bd528函数后产生的,
所以我们接着在此函数处下断点运行程序来到此处F7进入发现其代码逻辑:
服了原来就是c语言函数atof( )eax是参数,而eax刚好指向我们输入的序列号的后五位(代码我就不贴了,其实就是atof函数)
所以第二个关键函数就是调用了atof( )函数,返回我们输入序列号后五位所表示的十进制数值。
我们把这两个关键函数都分析了可以写出程序产生一个能够让 第一个关键函数返回值的后16位 == 第二个关键函数返回值的序列号
这里我就粘贴写的程序了,直接给出一个能满足上述条件的序列号:“61792262536446053268598766557788952812559488517686”
我们运行程序重新输入序列号后运行程序其执行了跳转( 不会弹出注册失败 )。
然后我们接着F8向下分析发现关键跳转处: 我们不用先不用管其内部的处理算法,只要看其宏观上的逻辑
其就是在比较 edx所指向的5个数据 是否 等于edi所指向的5个字符,如果有一个不等于其都会跳转到失败
那么我们就要知道这5个数据 和 这5个字符是怎么产生的。
下面我们就先来分析那5个数据是怎么产生的吧,edx指向那5个数据,edx值为0x0019e668004A111A . 8985 18FFFFFF mov dword ptr ss:[ebp-0xE8],eax
004A1120 . 8DB5 00FFFFFF lea esi,dword ptr ss:[ebp-0x100]
004A1126 . 33DB xor ebx,ebx ; ebx = 0
004A1128 > 8B95 18FFFFFF mov edx,dword ptr ss:[ebp-0xE8] ; do{
004A112E . 0FBE06 movsx eax,byte ptr ds:[esi] ; esi指向一个含有5个字符的字符串
004A1131 . 0FBE0A movsx ecx,byte ptr ds:[edx] ; edx指向5个数据
004A1134 . 83C1 EC add ecx,-0x14 ; ecx = ecx - 0x14
004A1137 . 3BC1 cmp eax,ecx
004A1139 . 0F85 80000000 jnz 屏录专家.004A11BF ; if(eax == ecx)
004A113F . 83FB 03 cmp ebx,0x3 ; {
004A1142 . 75 6A jnz X屏录专家.004A11AE ; if(ebx == 3)
004A1144 . 81C7 444D0000 add edi,0x4D44 ; {
004A114A . 89BD A0F6FFFF mov dword ptr ss:[ebp-0x960],edi ; edi = edi + 0x4d44
004A1150 . DB85 A0F6FFFF fild dword ptr ss:[ebp-0x960] ; st = edi * 3.14
004A1156 . DC0D 58194A00 fmul qword ptr ds:[0x4A1958] ; st = st * 0.1594896331738427110
004A115C . DB2D 60194A00 fld tbyte ptr ds:[0x4A1960]
004A1162 . DEC9 fmulp st(1),st
004A1164 . E8 5FCA1200 call 屏录专家.005CDBC8 ; eax = int(st)
004A1169 . 8BF8 mov edi,eax ; edi = eax
004A116B . 8BC7 mov eax,edi
004A116D . B9 A0860100 mov ecx,0x186A0 ; ecx = 0x186a0
004A1172 . 99 cdq
004A1173 . F7F9 idiv ecx ; edx:eax = eax / ecx
004A1175 . 8BFA mov edi,edx ; - edi = edx
004A1177 . 33C0 xor eax,eax ; eax = 0
004A1179 . 8985 3CFFFFFF mov dword ptr ss:[ebp-0xC4],eax ; [ebp - 0xc4] = 0
004A117F . 33D2 xor edx,edx ; edx =0
004A1181 . 8D85 A4FEFFFF lea eax,dword ptr ss:[ebp-0x15C]
004A1187 > 0FBE08 movsx ecx,byte ptr ds:[eax] ; 把那20个字符的前19个累加到 [ebp - 0xc4]
004A118A . 018D 3CFFFFFF add dword ptr ss:[ebp-0xC4],ecx
004A1190 . 42 inc edx
004A1191 . 40 inc eax
004A1192 . 83FA 13 cmp edx,0x13
004A1195 .^ 7C F0 jl X屏录专家.004A1187
004A1197 . 8B85 3CFFFFFF mov eax,dword ptr ss:[ebp-0xC4] ; eax = [ebp - 0xc4]
004A119D . B9 0A000000 mov ecx,0xA ; ecx = 0xa
004A11A2 . 99 cdq
004A11A3 . F7F9 idiv ecx ; edx:eax = eax / ecx
004A11A5 . 83C2 30 add edx,0x30 ; edx = edx + 0x30
004A11A8 . 8995 3CFFFFFF mov dword ptr ss:[ebp-0xC4],edx ; [ebp - 0xc4] = edx
004A11AE > 43 inc ebx ; }
004A11AF . FF85 18FFFFFF inc dword ptr ss:[ebp-0xE8]
004A11B5 . 46 inc esi ; ebx++
004A11B6 . 83FB 05 cmp ebx,0x5 ; esi++
004A11B9 .^ 0F8C 69FFFFFF jl 屏录专家.004A1128 ; }while(ebx < 5)
004A11BF > 83FB 05 cmp ebx,0x5
004A11C2 . 0F8C BE060000 jl 屏录专家.004A1886 ; 不能跳(跳转就失败)
我们带数据窗口中找到搜索0x0019e668,然后我们对此处的内存下内存写入断点,再次运行程序程序会停在其产生的地方。
我们发现这5个数据实际是送地址0x05103110地址处复制过来的20个字符之中的前5字符。那我们就需要跟踪看0x05103110地址处的数据是怎么产生的
方法和上面一样我们在数据窗口中搜索0x05103110然后对此处的20个字符下内存写入断点,再次运行程序其会停在其产生处。
我们发现0x05103110地址处的20个字符是从地址0x0019dda4(0x0019b4 - 0x10)处传送来的
那好我们接着用上述方法在数据窗口中搜索0x0019dda4然后对此处的20个字符下内存写入断点(这里注意要把上面我们对0x05103110处下的内存写入断点删除)
运行程序,程序会停在其产生处。但是我们发现其会先对此处内存清0(此时程序肯定会停止,我们只需继续运行)。
然后我们发现其会将我们输入的序列号的前40个字符复制到这块内存中。
其复制完之后我们继续点击运行其又会停止,我们分析此处代码的算法。
的出我们追踪的此20个字符产生的算法是:先把我们输入的序列号的前40个字符的第3个和第39个,第5个和第26个,第10个和第32个字符分别互换后,
再每两个字符一组转化为其对应的十进制数值 + 9 + ebx/2得到的值挨边存到我们追踪的那块内存中,循环20次(ebx是计数器)。
我们知道这20个字符是如何产生的之后我们在去看那与这20个字符的前5个数据比较的 那另外5个字符是怎么产生的。(别忘取消所有的内存写入断点)
我们运行到原来的判断处发现此五个字符的地址为0x0019e6c4,
同样我们在数据窗口对此地址的内存下内存写入断点,运行程序后其会停在其产生处。
我们发现那5个字符实际是 我们的变换后的机器码的前20位(3位和19位,5位和16位,9位和12位互换。)的每一位
和我们的用户名的每一位进行异或后产生的值累加后 + 0x3039 -----》得到的值转化为对应的字符(即调用itoa函数)。
现在知道了那20个字符的前5个数据产生的算法,以及与其比较的5个字符的产生算法了。(其需要对应相等才能不弹出注册失败)
因为这五个字符是用户名和变换后的机器码产生的,又因为这5个数据是我们输入的序列号的前10个两两一组产生的,
所以我们由用户名和注册码就可以唯一确定正确序列号的前10个字符了。
然后由下面的算法我们又能确定第11位和第12位字符。我们确定了前12位字符,然后我们随机生成后面的38位字符组成50个字符的序列号后。
由下面算法得最后两个字符还得满足一定条件才能成功。
最后的满足条件序列号的算法描述我写的一点都不好,我发现我这分析越写越乱,哎和大佬没法比。004A1126 . 33DB xor ebx,ebx ; ebx = 0
004A1128 > 8B95 18FFFFFF mov edx,dword ptr ss:[ebp-0xE8] ; do{
004A112E . 0FBE06 movsx eax,byte ptr ds:[esi] ; esi指向一个含有5个字符的字符串
004A1131 . 0FBE0A movsx ecx,byte ptr ds:[edx] ; edx指向一个含有20个字符的字符串
004A1134 . 83C1 EC add ecx,-0x14 ; ecx = ecx - 0x14
004A1137 . 3BC1 cmp eax,ecx
004A1139 . 0F85 80000000 jnz 屏录专家.004A11BF ; if(eax == ecx)
004A113F . 83FB 03 cmp ebx,0x3 ; {
004A1142 . 75 6A jnz X屏录专家.004A11AE ; if(ebx == 3)
004A1144 . 81C7 444D0000 add edi,0x4D44 ; {
004A114A . 89BD A0F6FFFF mov dword ptr ss:[ebp-0x960],edi ; edi = edi + 0x4d44
004A1150 . DB85 A0F6FFFF fild dword ptr ss:[ebp-0x960] ; st = edi * 3.14
004A1156 . DC0D 58194A00 fmul qword ptr ds:[0x4A1958] ; st = st * 0.1594896331738427110
004A115C . DB2D 60194A00 fld tbyte ptr ds:[0x4A1960]
004A1162 . DEC9 fmulp st(1),st
004A1164 . E8 5FCA1200 call 屏录专家.005CDBC8 ; eax = int(st)
004A1169 . 8BF8 mov edi,eax ; edi = eax
004A116B . 8BC7 mov eax,edi
004A116D . B9 A0860100 mov ecx,0x186A0 ; ecx = 0x186a0
004A1172 . 99 cdq
004A1173 . F7F9 idiv ecx ; edx:eax = eax / ecx
004A1175 . 8BFA mov edi,edx ; - edi = edx
004A1177 . 33C0 xor eax,eax ; eax = 0
004A1179 . 8985 3CFFFFFF mov dword ptr ss:[ebp-0xC4],eax ; [ebp - 0xc4] = 0
004A117F . 33D2 xor edx,edx ; edx =0
004A1181 . 8D85 A4FEFFFF lea eax,dword ptr ss:[ebp-0x15C]
004A1187 > 0FBE08 movsx ecx,byte ptr ds:[eax] ; 把那20个字符的前19个累加到 [ebp - 0xc4]
004A118A . 018D 3CFFFFFF add dword ptr ss:[ebp-0xC4],ecx
004A1190 . 42 inc edx
004A1191 . 40 inc eax
004A1192 . 83FA 13 cmp edx,0x13
004A1195 .^ 7C F0 jl X屏录专家.004A1187
004A1197 . 8B85 3CFFFFFF mov eax,dword ptr ss:[ebp-0xC4] ; eax = [ebp - 0xc4]
004A119D . B9 0A000000 mov ecx,0xA ; ecx = 0xa
004A11A2 . 99 cdq
004A11A3 . F7F9 idiv ecx ; edx:eax = eax / ecx
004A11A5 . 83C2 30 add edx,0x30 ; edx = edx + 0x30
004A11A8 . 8995 3CFFFFFF mov dword ptr ss:[ebp-0xC4],edx ; [ebp - 0xc4] = edx
004A11AE > 43 inc ebx ; }
004A11AF . FF85 18FFFFFF inc dword ptr ss:[ebp-0xE8]
004A11B5 . 46 inc esi ; ebx++
004A11B6 . 83FB 05 cmp ebx,0x5 ; esi++
004A11B9 .^ 0F8C 69FFFFFF jl 屏录专家.004A1128 ; }while(ebx < 5)
004A11BF > 83FB 05 cmp ebx,0x5
004A11C2 . 0F8C BE060000 jl 屏录专家.004A1886 ; 不能跳(跳转就失败)
004A11C8 . 0FBE85 B7FEFF>movsx eax,byte ptr ss:[ebp-0x149] ; 看那20个字符的最后一个字符是不是等于[ebp - 0xc4]
004A11CF . 3B85 3CFFFFFF cmp eax,dword ptr ss:[ebp-0xC4]
004A11D5 . 74 09 je X屏录专家.004A11E0 ; 或者最后一个字符大于等于0x41
004A11D7 . 83F8 41 cmp eax,0x41
004A11DA . 0F8C A6060000 jl 屏录专家.004A1886 ; 不能跳(跳转就失败)
004A11E0 > 8BC7 mov eax,edi ; eax = edi
004A11E2 . B9 0A000000 mov ecx,0xA ; ecx = 0xa
004A11E7 . 99 cdq
004A11E8 . F7F9 idiv ecx ; edx = eax % ecx
004A11EA . 0FBE841D A4FE>movsx eax,byte ptr ss:[ebp+ebx-0x15C] ; eax = 第6个字符
004A11F2 . 83C0 BF add eax,-0x41 ; eax = eax - 0x41
004A11F5 . 2BC2 sub eax,edx ; eax = eax - edx
004A11F7 . 8985 40FFFFFF mov dword ptr ss:[ebp-0xC0],eax
004A11FD . 83BD 40FFFFFF>cmp dword ptr ss:[ebp-0xC0],0x0 ; if(eax == 0 || eax == 9)
004A1204 . 74 0D je X屏录专家.004A1213 ; 成功
004A1206 . 83BD 40FFFFFF>cmp dword ptr ss:[ebp-0xC0],0x9 ; else
004A120D . 0F85 EC050000 jnz 屏录专家.004A17FF ; 其跳转就失败
004A1213 > 66:C785 5CFFF>mov word ptr ss:[ebp-0xA4],0x104
004A121C . BA 5CCF6200 mov edx,屏录专家.0062CF5C
004A1221 . 8D45 B4 lea eax,dword ptr ss:[ebp-0x4C]
004A1224 . E8 9B411300 call 屏录专家.005D53C4
004A1229 . FF85 68FFFFFF inc dword ptr ss:[ebp-0x98]
004A122F . 8B00 mov eax,dword ptr ds:[eax]
004A1231 . E8 3E4B0E00 call 屏录专家.00585D74 ; 成功