且行且远
分类: 逆向手札 由 ssfighter 于 2006年5月24日 发表

看了水木Crack版上以前peansen学长发的一篇Flashget限制线程数的修改方法,尝试着自己用OllyDbg跟了一下,发现还不算很难, odbg对这种C++写的程序支持的很好,用起来很方便,这篇文章我希望自己尽量写的详细一点,以前的东西我都是不该详细的地方写的特别详细,该认真分析的地方都一笔带过了:(

首先,在默认下载属性的地方,把文件分成10同时下载的地方改成11,弹出一个窗口,显示”Please enter an integer between 1 and 10.”,先对FlashGet侦壳,发现无壳,直接用OllyICE载入,先找一下字符串参考,发现找不到,那就直接对API函数下断点bp MessageBoxA。
启动之后仍然把默认下载属性里面的10改为11,程序被断下,按Ctrl+F9从系统领空返回到程序领空来到这里:
004C4BD7 /$ 55 push ebp
004C4BD8 |. 8BEC mov ebp, esp
004C4BDA |. 81EC 14010000 sub esp, 114
004C4BE0 |. 53 push ebx
004C4BE1 |. 56 push esi
004C4BE2 |. 57 push edi
004C4BE3 |. 33DB xor ebx, ebx
004C4BE5 |. 8BF9 mov edi, ecx
004C4BE7 |. 53 push ebx
004C4BE8 |. 897D F0 mov ss:[ebp-10], edi
004C4BEB |. E8 B9FFFFFF call flashget.004C4BA9
004C4BF0 |. 8D45 FC lea eax, ss:[ebp-4]
004C4BF3 |. 50 push eax
004C4BF4 |. 53 push ebx
004C4BF5 |. E8 55010000 call flashget.004C4D4F
004C4BFA |. 33F6 xor esi, esi
004C4BFC |. 3BC3 cmp eax, ebx
004C4BFE |. 8945 F4 mov ss:[ebp-C], eax
004C4C01 |. 74 18 je short flashget.004C4C1B
004C4C03 |. 53 push ebx ; /lParam
004C4C04 |. 53 push ebx ; |wParam
004C4C05 |. 68 76030000 push 376 ; |Message = MSG(376)
004C4C0A |. FF75 FC push dword ptr ss:[ebp-4] ; |hWnd
004C4C0D |. FF15 6C574E00 call near ds:[<&USER32.SendMessageA>] ; \SendMessageA
004C4C13 |. 3BC3 cmp eax, ebx
004C4C15 |. 74 04 je short flashget.004C4C1B
004C4C17 |. 8BF0 mov esi, eax
004C4C19 |. EB 0A jmp short flashget.004C4C25
004C4C1B |> 3BFB cmp edi, ebx
004C4C1D |. 74 06 je short flashget.004C4C25
004C4C1F |. 8DB7 9C000000 lea esi, ds:[edi+9C]
004C4C25 |> 3BF3 cmp esi, ebx
004C4C27 |. 895D F8 mov ss:[ebp-8], ebx
004C4C2A |. 74 13 je short flashget.004C4C3F
004C4C2C |. 8B06 mov eax, ds:[esi]
004C4C2E |. 8945 F8 mov ss:[ebp-8], eax
004C4C31 |. 8B45 10 mov eax, ss:[ebp+10]
004C4C34 |. 3BC3 cmp eax, ebx
004C4C36 |. 74 07 je short flashget.004C4C3F
004C4C38 |. 05 00000300 add eax, 30000
004C4C3D |. 8906 mov ds:[esi], eax
004C4C3F |> 8B5D 0C mov ebx, ss:[ebp+C]
004C4C42 |. F6C3 F0 test bl, 0F0
004C4C45 |. 75 17 jnz short flashget.004C4C5E
004C4C47 |. 8BC3 mov eax, ebx
004C4C49 |. 83E0 0F and eax, 0F
004C4C4C |. 83F8 01 cmp eax, 1
004C4C4F |. 76 0A jbe short flashget.004C4C5B
004C4C51 |. 83F8 02 cmp eax, 2
004C4C54 |. 76 08 jbe short flashget.004C4C5E
004C4C56 |. 83F8 04 cmp eax, 4
004C4C59 |. 77 03 ja short flashget.004C4C5E
004C4C5B |> 83CB 30 or ebx, 30
004C4C5E |> 85FF test edi, edi
004C4C60 |. 74 05 je short flashget.004C4C67
004C4C62 |. 8B7F 78 mov edi, ds:[edi+78]
004C4C65 |. EB 1A jmp short flashget.004C4C81
004C4C67 |> 8D85 ECFEFFFF lea eax, ss:[ebp-114]
004C4C6D |. 68 04010000 push 104 ; /BufSize = 104 (260.)
004C4C72 |. 50 push eax ; |PathBuffer
004C4C73 |. 6A 00 push 0 ; |hModule = NULL
004C4C75 |. 8DBD ECFEFFFF lea edi, ss:[ebp-114] ; |
004C4C7B |. FF15 A8524E00 call near ds:[<&KERNEL32.GetModuleFil>; \GetModuleFileNameA
004C4C81 |> 53 push ebx ; /Style
004C4C82 |. 57 push edi ; |Title
004C4C83 |. FF75 08 push dword ptr ss:[ebp+8] ; |Text
004C4C86 |. FF75 F4 push dword ptr ss:[ebp-C] ; |hOwner
004C4C89 |. FF15 9C554E00 call near ds:[<&USER32.MessageBoxA>] ; \MessageBoxA
004C4C8F |. 85F6 test esi, esi ; flashget.00519B5C
004C4C91 |. 8BF8 mov edi, eax

原本以为这里会有判断的地方,但是没有找到,按照peansen说的,继续向上找调用这个模块的地方,具体跟踪的方法就是紧跟出错的字符串,从4C4BD7处可以看到,这个调用是来自于4C4CED,再来到这里:
004C4CBE /$ 55 push ebp
004C4CBF |. 8BEC mov ebp, esp
004C4CC1 |. E8 6DA10000 call flashget.004CEE33
004C4CC6 |. 8B40 04 mov eax, ds:[eax+4]
004C4CC9 |. 85C0 test eax, eax
004C4CCB |. 74 15 je short flashget.004C4CE2
004C4CCD |. FF75 10 push dword ptr ss:[ebp+10]
004C4CD0 |. 8B10 mov edx, ds:[eax]
004C4CD2 |. 8BC8 mov ecx, eax
004C4CD4 |. FF75 0C push dword ptr ss:[ebp+C]
004C4CD7 |. FF75 08 push dword ptr ss:[ebp+8]
004C4CDA |. FF92 8C000000 call near ds:[edx+8C]
004C4CE0 |. EB 10 jmp short flashget.004C4CF2
004C4CE2 |> FF75 10 push dword ptr ss:[ebp+10] ; /Arg3
004C4CE5 |. 33C9 xor ecx, ecx ; |
004C4CE7 |. FF75 0C push dword ptr ss:[ebp+C] ; |Arg2
004C4CEA |. FF75 08 push dword ptr ss:[ebp+8] ; |Arg1
004C4CED |. E8 E5FEFFFF call flashget.004C4BD7 ; \flashget.004C4BD7
004C4CF2 |> 5D pop ebp
004C4CF3 \. C2 0C00 retn 0C

对4C4CBE这里下断点,发现此时出错的字符串仍然是已经压入堆栈了,查看堆栈,返回到4C3B5D处,就是这里:
004C3AF5 /$ B8 A42B4E00 mov eax, flashget.004E2BA4
004C3AFA |. E8 5919FEFF call flashget.004A5458
004C3AFF |. 83EC 40 sub esp, 40
004C3B02 |. 57 push edi
004C3B03 |. 8B7D 08 mov edi, ss:[ebp+8]
004C3B06 |. 833F 00 cmp dword ptr ds:[edi], 0
004C3B09 |. 74 6E je short flashget.004C3B79
004C3B0B |. 56 push esi
004C3B0C |. 8B35 F0554E00 mov esi, ds:[<&USER32.wsprintfA>] ; USER32.wsprintfA
004C3B12 |. FF75 0C push dword ptr ss:[ebp+C]
004C3B15 |. 8D45 B4 lea eax, ss:[ebp-4C]
004C3B18 |. FF75 14 push dword ptr ss:[ebp+14] ; |Format
004C3B1B |. 50 push eax ; |s
004C3B1C |. FFD6 call near esi ; \wsprintfA
004C3B1E |. 83C4 0C add esp, 0C
004C3B21 |. 8D45 D4 lea eax, ss:[ebp-2C]
004C3B24 |. FF75 10 push dword ptr ss:[ebp+10]
004C3B27 |. FF75 14 push dword ptr ss:[ebp+14]
004C3B2A |. 50 push eax
004C3B2B |. FFD6 call near esi
004C3B2D |. A1 70545100 mov eax, ds:[515470]
004C3B32 |. 83C4 0C add esp, 0C
004C3B35 |. 8945 08 mov ss:[ebp+8], eax
004C3B38 |. 8D45 D4 lea eax, ss:[ebp-2C]
004C3B3B |. 8365 FC 00 and dword ptr ss:[ebp-4], 0
004C3B3F |. 50 push eax
004C3B40 |. 8D45 B4 lea eax, ss:[ebp-4C]
004C3B43 |. 50 push eax
004C3B44 |. 8D45 08 lea eax, ss:[ebp+8]
004C3B47 |. FF75 18 push dword ptr ss:[ebp+18]
004C3B4A |. 50 push eax
004C3B4B |. E8 33200000 call flashget.004C5B83
004C3B50 |. FF75 18 push dword ptr ss:[ebp+18] ; /Arg3
004C3B53 |. 6A 30 push 30 ; |Arg2 = 00000030
004C3B55 |. FF75 08 push dword ptr ss:[ebp+8] ; |Arg1
004C3B58 |. E8 61110000 call flashget.004C4CBE ; \flashget.004C4CBE

这里应该是对出错的字符串进行处理的地方,但是这并不是我们需要的,是判断线程数超过最大值之后出错来到的这里,因此还要往前返回,按堆栈的提示,回到4C3BAB出,来到这里:
004C3B88 /$ 55 push ebp
004C3B89 |. 8BEC mov ebp, esp
004C3B8B |. 8B45 0C mov eax, ss:[ebp+C]
004C3B8E |. 3B45 10 cmp eax, ss:[ebp+10]
004C3B91 |. 7C 05 jl short flashget.004C3B98
004C3B93 |. 3B45 14 cmp eax, ss:[ebp+14]
004C3B96 |. 7E 18 jle short flashget.004C3BB0
004C3B98 |> 68 12F10000 push 0F112
004C3B9D |. 68 B4E45000 push flashget.0050E4B4 ; ASCII “%ld”
004C3BA2 |. FF75 14 push dword ptr ss:[ebp+14]
004C3BA5 |. FF75 10 push dword ptr ss:[ebp+10]
004C3BA8 |. FF75 08 push dword ptr ss:[ebp+8]
004C3BAB |. E8 45FFFFFF call flashget.004C3AF5
004C3BB0 |> 5D pop ebp
004C3BB1 \. C2 1000 retn 10
这里就是判断添入的数值是否满足条件的地方,其中ss:[ebp+10]和ss:[ebp+14]分别是01和0A,也就是说添入的数值要介于1和10之间,如果不满足就会进入4C3BAB处的call,就会弹出那个对话框。我们不关心最小值1,我们关心的是最大值0A,我们希望知道知道这个ss: [ebp+14]是什么时候被压入堆栈的,因此还要继续返回到上层调用,观察堆栈,回到40CC34,来到这里:
0040CA90 . 6A FF push -1
0040CA92 . 68 C05E4D00 push flashget.004D5EC0 ; SE 处理程序安装
0040CA97 . 64:A1 0000000>mov eax, fs:[0]
0040CA9D . 50 push eax
0040CA9E . 64:8925 00000>mov fs:[0], esp
0040CAA5 . 83EC 20 sub esp, 20
0040CAA8 . A1 70545100 mov eax, ds:[515470]
0040CAAD . 53 push ebx
0040CAAE . 55 push ebp
0040CAAF . 56 push esi
0040CAB0 . 57 push edi
0040CAB1 . 8BF1 mov esi, ecx
0040CAB3 . 894424 10 mov ss:[esp+10], eax
0040CAB7 . 8B7C24 40 mov edi, ss:[esp+40]
0040CABB . C74424 38 000>mov dword ptr ss:[esp+38], 0
0040CAC3 . 833F 00 cmp dword ptr ds:[edi], 0
0040CAC6 . 0F84 89030000 je flashget.0040CE55
0040CACC . 894424 18 mov ss:[esp+18], eax
0040CAD0 . 8B86 90000000 mov eax, ds:[esi+90]
0040CAD6 . C64424 38 01 mov byte ptr ss:[esp+38], 1
0040CADB . 85C0 test eax, eax
0040CADD . 75 6B jnz short flashget.0040CB4A
0040CADF . 8D4424 10 lea eax, ss:[esp+10]
0040CAE3 . 50 push eax ; /Arg3
0040CAE4 . 68 E9030000 push 3E9 ; |Arg2 = 000003E9
0040CAE9 . 57 push edi ; |Arg1
0040CAEA . E8 106E0B00 call flashget.004C38FF ; \flashget.004C38FF
0040CAEF . 8B4C24 10 mov ecx, ss:[esp+10]
0040CAF3 . 8B41 F8 mov eax, ds:[ecx-8]
0040CAF6 . 85C0 test eax, eax
0040CAF8 . 74 20 je short flashget.0040CB1A
0040CAFA . 51 push ecx
0040CAFB . 8D5424 14 lea edx, ss:[esp+14]
0040CAFF . 8BCC mov ecx, esp
0040CB01 . 896424 44 mov ss:[esp+44], esp
0040CB05 . 52 push edx
0040CB06 . E8 E1BC0A00 call flashget.004B87EC
0040CB0B . 8B8E 8C000000 mov ecx, ds:[esi+8C] ; |
0040CB11 . E8 3A170300 call flashget.0043E250 ; \flashget.0043E250
0040CB16 . 85C0 test eax, eax
0040CB18 . 75 22 jnz short flashget.0040CB3C
0040CB1A > 8B4424 10 mov eax, ss:[esp+10]
0040CB1E . 8B48 F8 mov ecx, ds:[eax-8]
0040CB21 . 85C9 test ecx, ecx
0040CB23 . 0F85 98000000 jnz flashget.0040CBC1
0040CB29 . 8B8E 8C000000 mov ecx, ds:[esi+8C]
0040CB2F . E8 2C5F0300 call flashget.00442A60
0040CB34 . 85C0 test eax, eax
0040CB36 . 0F84 85000000 je flashget.0040CBC1
0040CB3C > 8D4C24 10 lea ecx, ss:[esp+10]
0040CB40 . 51 push ecx
0040CB41 . 8D4C24 1C lea ecx, ss:[esp+1C]
0040CB45 . E8 66C00A00 call flashget.004B8BB0
0040CB4A > 8D5424 14 lea edx, ss:[esp+14]
0040CB4E . 52 push edx
0040CB4F . 68 E1040000 push 4E1
0040CB54 . 57 push edi
0040CB55 . E8 F76D0B00 call flashget.004C3951
0040CB5A . 8B6C24 14 mov ebp, ss:[esp+14]
0040CB5E . 8B8E 8C000000 mov ecx, ds:[esi+8C]
0040CB64 . 33C0 xor eax, eax
0040CB66 . 85ED test ebp, ebp
0040CB68 . 0F94C0 sete al
0040CB6B . 50 push eax
0040CB6C . E8 2FBB0300 call flashget.004486A0
0040CB71 . 8D4C24 10 lea ecx, ss:[esp+10]
0040CB75 . 51 push ecx ; /Arg3
0040CB76 . 68 ED030000 push 3ED ; |Arg2 = 000003ED
0040CB7B . 57 push edi ; |Arg1
0040CB7C . E8 7E6D0B00 call flashget.004C38FF ; \flashget.004C38FF
0040CB81 . 51 push ecx
0040CB82 . 8D5424 14 lea edx, ss:[esp+14]
0040CB86 . 8BCC mov ecx, esp
0040CB88 . 896424 44 mov ss:[esp+44], esp
0040CB8C . 52 push edx
0040CB8D . E8 5ABC0A00 call flashget.004B87EC
0040CB92 . 8B8E 8C000000 mov ecx, ds:[esi+8C]
0040CB98 . E8 E3AC0300 call flashget.00447880
0040CB9D . 83BE 90000000>cmp dword ptr ds:[esi+90], 2
0040CBA4 . 74 62 je short flashget.0040CC08
0040CBA6 . 8D4424 10 lea eax, ss:[esp+10]
0040CBAA . 50 push eax ; /Arg3
0040CBAB . 68 EA030000 push 3EA ; |Arg2 = 000003EA
0040CBB0 . 57 push edi ; |Arg1
0040CBB1 . E8 496D0B00 call flashget.004C38FF ; \flashget.004C38FF
0040CBB6 . 8B4C24 10 mov ecx, ss:[esp+10]
0040CBBA . 8B41 F8 mov eax, ds:[ecx-8]
0040CBBD . 85C0 test eax, eax
0040CBBF . 75 2B jnz short flashget.0040CBEC
0040CBC1 > 6A FF push -1
0040CBC3 . 6A 00 push 0
0040CBC5 . 68 21EF0000 push 0EF21
0040CBCA . E8 D1240100 call flashget.0041F0A0
0040CBCF . 83C4 0C add esp, 0C
0040CBD2 . 8BCF mov ecx, edi
0040CBD4 . E8 4F6B0B00 call flashget.004C3728
0040CBD9 > 8D4C24 18 lea ecx, ss:[esp+18]
0040CBDD . C64424 38 00 mov byte ptr ss:[esp+38], 0
0040CBE2 . E8 90BE0A00 call flashget.004B8A77
0040CBE7 . E9 4D060000 jmp flashget.0040D239
0040CBEC > 51 push ecx
0040CBED . 8D5424 14 lea edx, ss:[esp+14]
0040CBF1 . 8BCC mov ecx, esp
0040CBF3 . 896424 44 mov ss:[esp+44], esp
0040CBF7 . 52 push edx
0040CBF8 . E8 EFBB0A00 call flashget.004B87EC
0040CBFD . 8B8E 8C000000 mov ecx, ds:[esi+8C]
0040CC03 . E8 B80F0300 call flashget.0043DBC0
0040CC08 > 8D4424 14 lea eax, ss:[esp+14]
0040CC0C . 50 push eax ; /Arg3
0040CC0D . 68 F4030000 push 3F4 ; |Arg2 = 000003F4
0040CC12 . 57 push edi ; |Arg1
0040CC13 . E8 5A6C0B00 call flashget.004C3872 ; \flashget.004C3872
0040CC18 . 6A 02 push 2
0040CC1A . E8 11700000 call flashget.00413C30
0040CC1F . 8BC8 mov ecx, eax
0040CC21 . E8 FA730000 call flashget.00414020
0040CC26 . 8B4C24 14 mov ecx, ss:[esp+14]
0040CC2A . 50 push eax ; /Arg4
0040CC2B . 6A 01 push 1 ; |Arg3 = 00000001
0040CC2D . 51 push ecx ; |Arg2
0040CC2E . 57 push edi ; |Arg1
0040CC2F . E8 546F0B00 call flashget.004C3B88 ; \flashget.004C3B88

同时这里我们需要重新启动一遍FlashGet,把堆栈锁定,观察这个0A是什么时候被压入到堆栈的。观察发现40CC21处的调用使得eax的值改变,而后系统将eax的0A压入堆栈,F7进入这个call,来到这里:

00414020 /$ 8B4424 04 mov eax, ss:[esp+4]
00414024 |. 83F8 5F cmp eax, 5F ; Switch (cases 2..214)
00414027 |. 0F8F DF020000 jg flashget.0041430C
0041402D |. 0F84 CA020000 je flashget.004142FD
00414033 |. 83C0 FE add eax, -2
00414036 |. 83F8 5C cmp eax, 5C
00414039 |. 0F87 E2050000 ja flashget.00414621
0041403F |. 33D2 xor edx, edx
00414041 |. 8A90 0C474100 mov dl, ds:[eax+41470C]
00414047 |. FF2495 284641>jmp near ds:[edx*4+414628]
0041404E |> 8B81 48010000 mov eax, ds:[ecx+148] ; Case 3D of switch 00414024
00414054 |. C2 0400 retn 4
00414057 |> 8B81 C4010000 mov eax, ds:[ecx+1C4] ; Case 39 of switch 00414024
0041405D |. 25 00200000 and eax, 2000
00414062 |. C2 0400 retn 4
00414065 |> 8B81 2C010000 mov eax, ds:[ecx+12C] ; Case 2A of switch 00414024
0041406B |. C2 0400 retn 4
0041406E |> 8B81 30010000 mov eax, ds:[ecx+130] ; Case 2B of switch 00414024
00414074 |. C2 0400 retn 4
00414077 |> 8B81 34010000 mov eax, ds:[ecx+134] ; Case 2E of switch 00414024
0041407D |. C2 0400 retn 4
00414080 |> 8B81 38010000 mov eax, ds:[ecx+138] ; Case 2C of switch 00414024
00414086 |. C2 0400 retn 4
00414089 |> 8B81 3C010000 mov eax, ds:[ecx+13C] ; Case 2D of switch 00414024
0041408F |. C2 0400 retn 4
00414092 |> 8B81 CC010000 mov eax, ds:[ecx+1CC] ; Case 2 of switch 00414024
注意了,就是这里,程序把ds:[00519C8C]的值0A送给了eax,然后后面的程序又把eax的值压入了堆栈,下面就是要看一下ds: [00519C8C]处的值是什么时候被写入的,因为系统刚启动时这里仍然是00,对这里下硬件写入断点,重新启动FlashGet

00414098 |. C2 0400 retn 4
0041409B |> 8B81 D0010000 mov eax, ds:[ecx+1D0] ; Case 3 of switch 00414024

运行后断在这里:
0041738D |. 6A 0A push 0A ; 最大限制
0041738F |. 68 98FC5000 push flashget.0050FC98 ; ASCII “Max Parallel Num”
00417394 |. 68 FCE45000 push flashget.0050E4FC ; ASCII “General”
00417399 |. 8BCE mov ecx, esi
0041739B |. 8986 E8000000 mov ds:[esi+E8], eax
004173A1 |. E8 1A7D0B00 call flashget.004CF0C0
004173A6 |. 83F8 1E cmp eax, 1E ; 和30比较
004173A9 |. 8986 CC010000 mov ds:[esi+1CC], eax
004173AF |. 7E 0A jle short flashget.004173BB ; 如果限制大于30就默认写为30
004173B1 |. C786 CC010000>mov dword ptr ds:[esi+1CC], 1E
004173BB |> 6A 08 push 8
呵呵,这里提示很明显,就是最大下载线程数的限制,需要注意的是0041738D处的push 0A就是最大限制,可以把这里改的稍微大一些,比如push 32(就是50),但是需要注意的是004173A6处还要和1E做比较,如果你改的数超过30,程序会自动把最大限制改成30,因此如果改的最大限制数超过30,就必须把这个cmp eax, 1E处的判定也修改一下,不过一般来说下载线程数30对于教育网来说就足够了,改的太大其实根本不会使下载速度变快,可能还会拖垮自己的电脑,很没有必要,我建议修改成1E就可以了,这样后面也不用改。

总结一下,简单修改的办法,用UltraEdit或类似的能进行16进制编辑的编辑器打开Flashget.exe文件,搜索6A0A6898FC5000,把其中的0A修改为1E就可以使最大进程数变为30了,如果还想变的更大些,就不仅仅要把这里改一下,而且还要把紧接在后面不远处的83F81E的1E也改为你修改的数值即可,也就是把判定换掉。需要注意的是这里只能把限制改成FF (即255)以内的数,也就是只能修改0A那一位,当然,想改成最大线程数是10000也可以,把那段判断的程序整个不要,重新改写一下源程序也就行了,也不难的,不过改成那么BT的数完全没意义,对下载速度没有啥贡献。



发表评论

昵称:  (必须)
邮件:  (必须)
网址: 
评论: