Spørgsmål:
Hvordan håndteres statisk hukommelsesallokering, mens man ændrer en eksekverbar?
Zarathos
2014-05-08 05:59:15 UTC
view on stackexchange narkive permalink

Jeg er ikke ny på StackExchange, men jeg er helt ny inden for reverse engineering, så vær tålmodig med mig! : P

På nuværende tidspunkt har jeg at gøre med en eksekverbar fil, som jeg gerne vil ændre lidt til personlig brug; applikationens kildekode er ikke tilgængelig, så jeg kan kun ændre det eller prøve. Jeg bruger både IDA Pro 6.1 og OllyDBG 2.0 som værktøj.

For at være præcis vil jeg bare øge mængden af ​​CFG_ENTRY, som applikationen kan læse fra 500 til 1000 i metoden ReadCfgFile som tilsyneladende har en statisk hukommelsesregion forudlokaliseret ved kompileringstid:

  .text: 008F2860 ReadCfgFile proc nær ved ; DATA XREF: .rdata: 0137A1ECo.text: 008F2860 var_20 = dword ptr -20h.text: 008F2860 var_1C = dword ptr -1Ch.text: 008F2860 var_18 = dword ptr -18h.text: 008F2860 var_C = dword ptr -0Ch.text: 008F2860 var_4 = dword ptr -4.text: 008F2860 arg_0 = dword ptr 4.text: 008F2860 arg_4 = byte ptr 8.text: 008F2860.text: 008F2860 push 0FFFFFFFFh.text: 008F2862 mov eax, large fs: 0.text: 008F2868 push offset sub_1288B18.text: 008F286D push eax.text: 008F286E mov large fs: 0, esp.text: 008F2875 sub esp, 14h.text: 008F2878 push ebx.text: 008F2879 push ebp.text: 008F287A push esi.text: 008F287B skub edi.text: 008F287C mov edi, [esp + 30h + arg_0] .text: 008F2880 mov eax, [edi + 10h] .text: 008F2883 cmp eax, [edi + 8] .te xt: 008F2886 mov esi, ecx.text: 008F2888 jnb loc_8F2930.text: 008F288E mov edi, edi.text: 008F2890.text: 008F2890 loc_8F2890: .text: 008F2890 mov eax, [esi + 79954h] .text: 008F96 3E8h
.text: 008F289B jge loc_8F29DF.text: 008F28A1 mov edx, eax.text: 008F28A3 shl edx, 5.text: 008F28A6 lea ecx, [eax + 1] .text: 008F28A9 sub edx, eax.text: 008F28AB lea eax, [ eax + edx * 8] .text: 008F28AE mov [esi + 79954h], ecx.text: 008F28B4 push edi.text: 008F28B5 lea ecx, [esi + eax * 4 + 4] .text: 008F28B9 call ReadEDURecord.text: 008F28BE test al, al.text: 008F28C0 jz loc_8F2947.text: 008F28C6 mov eax, [esi + 79954h] .text: 008F28CC mov ecx, eax.text: 008F28CE shl ecx, 5.text: 008F28D1 sub ecx, eax.text: 008F28D3 lea edx, [eax + ecx * 8] .text: 008F28D6 mov ebp, [esi + edx * 4-3E0h] .text: 008F28DD lea eax, [esp + 30h + arg_0] .text: 008F28E1 lea ebx, [esi + 79958h] .text: 008F28E7 push eax.text: 008F28E8 mov ecx, ebx.text: 008F28EA mov [esp + 34h + arg_0], ebp.text: 008F28EE call sub_437DF0.text: 008F28F3 test eax, eax. tekst: 008F28F5 jz kort loc_8F2902.text: 008F28F7 cmp [esp + 30h + arg_4], 0.text: 008F28FC jz loc_8F2994.text: 008F2902.text: 008F2902 loc_8F2902: .text: 008F2902 mov ecx, [es]. : 008F2908 sub ecx, 1.text: 008F290B lea edx, [esp + 30h + arg_0] .text: 008F290F push edx.text: 008F2910 lea eax, [esp + 34h + var_20] .text: 008F2914 mov [esp + 34h + arg_0], ecx.text: 008F2918 push eax.text: 008F2919 mov ecx, ebx.text: 008F291B mov [esp + 38h + var_20], ebp.text: 008F291F call sub_437890
.text: 008F2924 mov ecx, [edi + 10h] .text: 008F2927 cmp ecx, [edi + 8] .text: 008F292A jb loc_8F2890.text: 008F2930.text: 008F2930 loc_8F2930: .text: 008F2930 pop edi.text: 008F2931 pop esi.text: 008F2932 pop ebp.text: 008F2933 mov al, 1.text: 008F2935 pop ebx.text: 008F2936 mov ecx, [esp + 20h + var_C] .text: 008F293A mov store fs: 0, ecx.text: 008F2941 add esp, 20h.text: 008F2944 retn 8.text: 008F2947.text: 008F2947 loc_8F2947: .text: 008F2947 push 0.text: 008F2949 call sub_D386E0.text: 008F294E add esp, 4. text: 008F2951 mov ecx, edi. tekst: 008F2953 mov esi, eax.text: 008F2955 call sub_D4D270.text: 008F295A push eax; ArgList.text: 008F295B push offset aErrMsg_1; Fejlmeddelelse.tekst: 008F2960 kald sub_D386E0.tekst: 008F2965 tilføj esp, 8. tekst: 008F2968 kald sub_D388C0.tekst: 008F296D lea edx, [esp + 30h + var_20]. Tekst: 008F2971 skub edx.tekst: 008F2972 lea ecx, [ esp + 34h + var_18] .text: 008F2976 mov [esp + 34h + var_20], eax.text: 008F297A mov [esp + 34h + var_1C], 640h.text: 008F2982 kald sub_403D60.text: 008F2987 mov [esp + 30h + var_4], 0.text: 008F298F jmp loc_8F2A27.text: 008F2994.text: 008F2994 loc_8F2994: .text: 008F2994 push 0.text: 008F2996 call sub_D386E0.text: 008F299B add esp, 4.text: 008F299. : 008F29A0 mov esi, eax.text: 008F29A2 call sub_D4D270.text: 008F29A7 push eax
.tekst: 008F29A8 push ebp; ArgList.text: 008F29A9 push offset aErrMsg_2; Fejlmeddelelse.tekst: 008F29AE kald sub_D386E0.text: 008F29B3 tilføj esp, 0Ch.tekst: 008F29B6 kald sub_D388C0.text: 008F29BB mov [esp + 30h + var_20], eax.text: 008F29BF lea eax, [esp + 30h + var_20] .text: 008F29C3 push eax.text: 008F29C4 lea ecx, [esp + 34h + var_18] .text: 008F29C8 mov [esp + 34h + var_1C], 640h.text: 008F29D0 call sub_403D60.text: 008F29D5 mov [esp + 30h + var_4], 1.text: 008F29DD jmp kort loc_8F2A27.text: 008F29DF.text: 008F29DF loc_8F29DF: .text: 008F29DF push 0.text: 008F29E1 kald sub_D386E0.text: 008F29E6 tilføj esp, 4.text: 008F29E. tekst: 008F29EB mov esi, eax.text: 008F29ED kald sub_D4D270.text: 008F29F2 push eax; ArgList.text: 008F29F3 push offset aErrMsg_0; Fejlmeddelelse.tekst: 008F29F8 kald sub_D386E0.tekst: 008F29FD tilføj esp, 8. tekst: 008F2A00 kald sub_D388C0.tekst: 008F2A05 lea ecx, [esp + 30h + var_20] .tekst: 008F2A09 push ecx.text: 008F2A0A leax esp + 34h + var_18] .text: 008F2A0E mov [esp + 34h + var_20], eax.text: 008F2A12 mov [esp + 34h + var_1C], 640h.text: 008F2A1A kald sub_403D60.text: 008F2A1F mov [esp + 30h + var_4], 2.text: 008F2A27.text: 008F2A27 loc_8F2A27: .text: 008F2A27 mov eax, [esp + 30h + var_18] .text: 008F2A2B test eax, eax.text: 008F2A2D jz kort loc_8F2A3A.text: 008F2. tekst: 008F2A30 push eax
.tekst: 008F2A31 kald ds: ?? $? 6U? $ char_traits @ D @ std @@@ std @@ YAAAV? $ basic_ostream @ DU? $ char_traits @ D @ std @@@ 0 @ AAV10 @ PBD @ Z; std :: operator<<<std :: char_traits<char>> (std :: basic_ostream<char, std :: char_traits<char>> &, char const *) tekst:. 008F2A37 add esp, 8.text: 008F2A3A.text: 008F2A3A loc_8F2A3A: .text: 008F2A3A lea ECx, [esp + 30h + var_18] .text: 008F2A3E mov [esp + 30h + var_4], 0FFFFFFFFh.text: 008F2A46 call sub_403DF0.text: 008F2A4B mov ecx, [esp + 30h + var_C] .text: 008F2A4F pop edi.text: 008F2A esi.text: 008F2A51 pop ebp.text: 008F2A52 xor al, al.text: 008F2A54 pop ebx.text: 008F2A55 mov large fs: 0, ecx.text: 008F2A5C add esp, 20h.text: 008F2A5F retn 8.text: 008F2A5F ReadCfgFile endp  

[EDIT 1 - Alt hvad jeg burde have kendt sinc i begyndelsen!]

Efter at have fulgt forslagene i svaret fra @sealed ... brugte jeg en klasseinspektør til at opdage den virtuelle funktionstabel, og jeg fandt den fulde klassedeskriptor. Nå ... faktisk er der to klasser, der henviser til min målmetode ReadCfgFile og ingen direkte opkald til den i hele den eksekverbare:

  .rdata: 0137A1D4; klasse DATABASE_TABLE<CFG_ENTRY, 500, usigneret int> [SI] O: 0, A: 0.rdata: 0137A1D4 dd offset ?? _ R4? $ DATABASE_TABLE @ UCFG_ENTRY @@ $ 0BPE @ I @@ 6B; RTTI Complete Object Locator.rdata: 0137A1D8; const DATABASE_TABLE<struct CFG_ENTRY, 500, usigneret int> VF Table.rdata: 0137A1D8 ?? _ 7? $ DATABASE_TABLE @ UCFG_ENTRY @@ $ 0BPE @ I @@ 6B @ dd offset sub_8EF0F; DATA XREF: sub_8EEFC0 + 1Do.rdata: 0137A1DC dd offset nullsub_648.rdata: 0137A1E0 dd offset sub_8EAB30
.rdata: 0137A1E4 dd offset sub_8EF060.rdata: 0137A1E8 dd offset sub_8EE500.rdata: 0137A1EC dd offset ReadCfgFile.rdata: 0137A1F0; klasse CFG_DB: DATABASE_TABLE<CFG_ENTRY, 500, usigneret int> [SI] O: 0, A: 0.rdata: 0137A1F0 dd offset ?? _ R4CFG_DB @@ 6B @; RTTI Complete Object Locator.rdata: 0137A1F4; const CFG_DB VFTable.rdata: 0137A1F4 ?? _ 7UNIT_DB @@ 6B @ dd offset sub_8EF2B0; DATA XREF: sub_8EF290 + 8o.rdata: 0137A1F8 dd offset nullsub_648.rdata: 0137A1FC dd offset sub_8EAB30.rdata: 0137A200 dd offset sub_8EF060.rdata: 0137A204 dd offset sub_8EE8B0dAd: offset kode> 

[EDIT 2 - Eventyret fortsætter! Yay!]

Efter at have læst @Guntram Blohms svar, undersøgte jeg mere for at indsamle og analysere de data, han foreslog. Den første ting, jeg gjorde, er at analysere den eksekverbare med PEiD, og ​​her er de oplysninger, jeg fik fra den:

  Compiler: Microsoft Visual C ++ 7.0 Method2 [Debug] Entropy: 6.24 (Ikke pakket) Linker Info: 7.10  

Når jeg indstiller et breakpoint på min ReadCfgFile -metode, her er hvad jeg får fra OllyDBG-stakken:

  CPU StackAddress Value ASCII Comments0018B2C0 [008EE644 D�. ; TILBAGE til myapp.008EE644  

Og 008EE644 er en lille del af følgende metode, der efter det jeg kan forstå leder efter konfigurationsfilen og starter rutinen til læsning, men uden et eksplicit opkald til ReadCfgFile (offset fremhævet):

  .text: 008EE5D0 sub_8EE5D0 proc near; KODE XREF: sub_411B20 + 2CBp.text: 008EE5D0 var_41 = byte ptr -41h.text: 008EE5D0 var_40 = dword ptr -40h.text: 008EE5D0 var_3C = dword ptr -3Ch.text: 008EE5D0 var_38 = byte ptr -38h. var_34 = dword ptr -34h.text: 008EE5D0 var_30 = dword ptr -30h.text: 008EE5D0 var_2C = byte ptr -2Ch.text: 008EE5D0 var_C = dword ptr -0Ch
.text: 008EE5D0 var_4 = dword ptr -4.text: 008EE5D0.text: 008EE5D0 push 0FFFFFFFFh.text: 008EE5D2 push offset SEH_8EE5D0.text: 008EE5D7 mov eax, large fs: 0.text: 008EE5DD push eax.DE mov: 00EE fs: 0, esp.text: 008EE5E5 sub esp, 38h.text: 008EE5E8 push ebx.text: 008EE5E9 push ebp.text: 008EE5EA mov ebx, ecx.text: 008EE5EC push offset aCfgFile; "application.cfg" .text: 008EE5F1 mov [esp + 50h + var_30], ebx.text: 008EE5F5 call sub_41BD00.text: 008EE5FA add esp, 4.text: 008EE5FD push eax.text: 008EE5FE lea ecx, [esp + 50h + var_38] .text: 008EE602 call sub_F018E0.text: 008EE607 xor ebp, ebp.text: 008EE609 push ebp.text: 008EE60A lea eax, [esp + 50h + var_38] .text: 008EE60E push eax.text: 008EE60F lea ecx, [esp + 54h + var_2C] .text: 008EE613 mov [esp + 54h + var_4], ebp.text: 008EE617 kald sub_D50170.text: 008EE61C lea ecx, [esp + 4Ch + var_38]; ugyldig * .text: 008EE620 mov byte ptr [esp + 4Ch + var_4], 2. tekst: 008EE625 kald sub_EFFE30.text: 008EE62A mov edx, [ebx] .text: 008EE62C mov ecx, ebx.text: 008EE62E mov [ebx + 7A938h], ebp.text: 008EE634 kald dword ptr [edx + 4] .text: 008EE637 mov eax, [ebx] .text: 008EE639 push ebp.text: 008EE63A lea ecx, [esp + 50h + var_2C] .text: 008EE63E skub ecx.text: 008EE63F mov ecx, ebx.text: 008EE641 kald dword ptr [eax + 14h]
.tekst: 008EE644; -------------------------------------------------- ------------------------- .text: 008EE644 test al, al; HER ER STAKHENVISNINGEN. Tekst: 008EE644; -------------------------------------------------- ------------------------- .text: 008EE646 jnz kort loc_8EE66C.text: 008EE648 lea ecx, [esp + 4Ch + var_2C] .text: 008EE64C mov [esp + 4Ch + var_4], 0FFFFFFFFh.text: 008EE654 kald sub_D4BB30.text: 008EE659 pop ebp.text: 008EE65A xor al, al.text: 008EE65C pop ebx.text: 008EE65D mov ecx, [esp + 44h + var_C] .text: 008EE661 mov large fs: 0, ecx.text: 008EE668 add esp, 44h.text: 008EE66B retn.text: 008EE66C.text: 008EE66C loc_8EE66C: .text: 008EE66C xor edx, edx.text: 008EE66E eller eax, 0FFFFFFFFh .text: 008EE671 mov dword_1986644, edx.text: 008EE677 mov dword_1986650, eax.text: 008EE67C push esi.text: 008EE67D mov dword_1986648, edx.text: 008EE683 mov dword_1986654, eax.text: 008EE688 push edi.text: 008EE689 mov dword_198664C, edx.text: 008EE68F mov dword_1986658, eax.text: 008EE694 xor edi, edi.text: 008EE696 cmp [ebx + 79954h], eb jle loc_8EE727.text: 008EE6A2 lea esi, [ebx + 40h] .text: 008EE6A5 jmp kort loc_8EE6B0.text: 008EE6A7 align 10h.text: 008EE6B0.text: 008EE6B0 loc_8EE6B0: .text: 008EE6B0 mov .x. 008EE6B2 mov cx, [esi + 92h] .tekst: 008EE6B9 lea eax, ds: 1986644h [eax * 2] .tekst: 008EE6C0 mov axe, [eax] .text: 008EE6C3 cmp økse, cx
.text: 008EE6C6 jnb kort loc_8EE6CA.text: 008EE6C8 mov eax, ecx.text: 008EE6CA.text: 008EE6CA loc_8EE6CA: .text: 008EE6CA mov ecx, [esi] .text: 008EE6CC mov ord ptr dword_1986644 [ecx *] .text: 008EE6D4 mov eax, [esi] .text: 008EE6D6 mov cx, [esi + 92h] .text: 008EE6DD lea eax, ds: 1986650h [eax * 2] .text: 008EE6E4 mov ax, [eax] .text: 008EE6E7 cmp ax, cx.text: 008EE6EA jb short loc_8EE6EE.text: 008EE6EC mov eax, ecx.text: 008EE6EE.text: 008EE6EE loc_8EE6EE: .text: 008EE6EE mov edx, [esi] .text: 008EE6F0 lea ecx, [esi- 3Ch] .text: 008EE6F3 mov word ptr dword_1986650 [edx * 2], ax.text: 008EE6FB call sub_8ED600.text: 008EE700 push eax.text: 008EE701 mov eax, [ebx + 7A938h] .text: 008EE707 push eax.text: 008EE708 call sub_F1E550.text: 008EE70D add edi, 1.text: 008EE710 add esp, 8.text: 008EE713 mov [ebx + 7A938h], eax.text: 008EE719 add esi, 3E4h.text: 008EE71F cmp edi , [ebx + 79954h] .text: 008EE725 jl kort loc_8EE6B0.text: 008EE727.text: 008EE727 loc_8EE727: .text: 008EE727 xor esi, esi.text: 008EE729 cmp dword_1667290, ebp.text: 008EE72h mov [esp ], esi.text: 008EE733 jbe loc_8EE840.text: 008EE739 lea esp, [esp + 0] .text: 008EE740.text: 008EE740 loc_8EE740: .text: 008EE740 cmp [ebx + 79954h], ebp.text: 008EE746 mov [esp + 54h + var_41], 0.text: 008EE74B mov [esp + 54h + var_40], ebp.text: 008EE74F mov [esp + 54h + var_34], ebp
.text: 008EE753 jle loc_8EE7D9.text: 008EE759 mov ebp, 1.text: 008EE75E mov ecx, esi.text: 008EE760 shl ebp, cl.text: 008EE762 lea edi, [ebx + 3B0h] .text: 008EE768.text: 008EE768 loc_8EE768: .text: 008EE768 cmp [esp + 54h + var_41], 0.text: 008EE76D jnz kort loc_8EE77F.text: 008EE76F test [edi-2Ch], ebp.text: 008EE772 jz kort loc_8EE77F.text: 008EE774 testbyte ptr [ edi + 3], 20h.text: 008EE778 jz kort loc_8EE77F.text: 008EE77A mov [esp + 54h + var_41], 1.text: 008EE77F.text: 008EE77F loc_8EE77F: .text: 008EE77F xor esi, esi.text: 008EE781 xor eax, eax.text: 008EE783.text: 008EE783 loc_8EE783: .text: 008EE783 mov ecx, [edi-24h] .text: 008EE786 test [eax + ecx], ebp.text: 008EE789 jz kort loc_8EE7AF.text: 008EE78B cmp eax, 10h.text: 008EE78E jnb loc_8EE89B.text: 008EE794 mov ecx, esi.text: 008EE796 shr ecx, 5.text: 008EE799 lea edx, [esp + ecx * 4 + 54h + var_40]. tekst: 008EE79D mov ecx, esi.text: 008EE79F og ecx, 1Fh.text: 008EE7A2 mov ebx, 1. tekst: 008EE7A7 shl ebx, cl.text: 008EE7A9 eller [edx], ebx.text: 008EE7AB mov ebx, [esp + 54h + var_30] .text: 008EE7AF.text: 008EE7AF loc_8EE7AF: .text: 008EE7AF add eax, 4.text: 008EE7B2 add esi, 1.text: 008EE7B5 cmp eax, 10h.text: 008EE7B8 jb short loc_8EE787.text: 00 mov eax, [esp + 54h + var_34] .text: 008EE7BE tilføj eax, 1. text: 008EE7C1 tilføj edi, 3E4h
.text: 008EE7C7 cmp eax, [ebx + 79954h] .text: 008EE7CD mov [esp + 54h + var_34], eax.text: 008EE7D1 jl kort loc_8EE768.text: 008EE7D3 mov esi, [esp + 54h + var_3C] .text: 008EE7D7 xor ebp, ebp.text: 008EE7D9.text: 008EE7D9 loc_8EE7D9: .text: 008EE7D9 push esi.text: 008EE7DA call sub_8D1490.text: 008EE7DF mov edi, eax.text: 008EE7E1 add esp by, 4.text [edi + 0BCh], 0.text: 008EE7EB jz short loc_8EE82D.text: 008EE7ED xor esi, esi.text: 008EE7EF cmp esi, 4.text: 008EE7F2 jnb loc_8EE8A4.text: 008EE7F8.text: 008EE7F8 loc_8EE7: 00: 00: 00: 00: 008EE7F8: mov ecx, esi.text: 008EE7FA og ecx, 1Fh.text: 008EE7FD mov edx, 1.text: 008EE802 shl edx, cl.text: 008EE804 mov ecx, esi.text: 008EE806 shr ecx, 5.text: 008EE809 add ecx, ecx.text: 008EE80B add ecx, ecx.text: 008EE80D test [esp + ecx + 54h + var_40], edx.text: 008EE811 setnz al .text: 008EE814 test al, al.text: 008EE816 jnz kort loc_8EE821.text: 008EE818 ikke edx.text: 008EE81A og [ecx + edi + 0C0h], edx.text: 008EE821.text: 008EE821 loc_8EE821: .text: 008EE821 esi, 1.text: 008EE824 cmp esi, 4.text: 008EE827 jb short loc_8EE7F8.text: 008EE829 mov esi, [esp + 54h + var_3C] .text: 008EE82D.text: 008EE82D loc_8EE82D: .text: 008EE82D add esi, 1 .text: 008EE830 cmp esi, dword_1667290.text: 008EE836 mov [esp + 54h + var_3C], esi.text: 008EE83A jb loc_8EE740.text: 008EE840
.text: 008EE840 loc_8EE840: .text: 008EE840 xor esi, esi.text: 008EE842 cmp [ebx + 79954h], ebp.text: 008EE848 jle short loc_8EE875.text: 008EE84A lea edi, [ebx + 108h] .text: 0088 tekst: 008EE850 loc_8EE850: .text: 008EE850 mov eax, [edi] .text: 008EE852 mov ecx, dword_16E9DC8.text: 008EE858 push eax; Str2.text: 008EE859 add ecx, 84h.text: 008EE85F call sub_10E86C0.text: 008EE864 add esi, 1.text: 008EE867 add edi, 3E4h.text: 008EE86D cmp esi, [ebx + 79954h] .text: 008EE873 jl kort loc_8 .text: 008EE875.text: 008EE875 loc_8EE875: .text: 008EE875 lea ecx, [esp + 54h + var_2C] .text: 008EE879 mov [esp + 54h + var_4], 0FFFFFFFFh.text: 008EE881 kald sub_D4BB30.text: 008EE886 mov ecx , [esp + 54h + var_C] .text: 008EE88A pop edi.text: 008EE88B pop esi.text: 008EE88C pop ebp.text: 008EE88D mov al, 1. tekst: 008EE88F pop ebx.text: 008EE890 mov store fs: 0, ecx.text: 008EE897 add esp, 44h.text: 008EE89A retn.text: 008EE89B.text: 008EE89B loc_8EE89B: .text: 008EE89B le en ecx, [esp + 54h + var_40] .text: 008EE89F jmp sub_8D0FE0.text: 008EE8A4.text: 008EE8A4 loc_8EE8A4: .text: 008EE8A4 lea ecx, [esp + 54h + var_40] .text: 008EE8A8 jmp sub_8D0FE.0 sub_8EE5D0 endp  

Den, jeg gravede lidt mere for at finde ud af CFG_DB -konstruktøren, som ser sådan ud (pseudokode fra IDA Pro):

  ugyldigt __thiscall sub_8EEFC0 (ugyldigt * dette) {ugyldigt * v1 = dette; // esi @ 1
* (_ DWORD *) dette = &DATABASE_TABLE<CFG_ENTRY_500_unsigned_int> :: _ vftable_; sub_8EE500 ((int) dette); sub_8EC030 ((char *) v1 + 502036); hvis (* ((_ DWORD *) v1 + 124503)) operator sletter __ (* ((ugyldig **) v1 + 124503)); * ((_ DWORD *) v1 + 124503) = 0; unknown_libname_2673 ((char *) v1 + 4, 0x3E4u, 500, sub_8EEA00);}  

Så det ser ud til, at "array" af CFG_ENTRY bliver øjeblikkeligt kaldet en metode, der hører til et andet bibliotek, der er knyttet til den eksekverbare fil. Til sidst satte jeg et brudpunkt i begyndelsen af ​​min ReadCfgFile -metode for at se, om markører, der sendes til det, kan være til hjælp:

  .text: 008F287A push esi == > esi = 00400000 [...] [...]. text: 008F2886 mov esi, ecx == > ecx = myapp.0190BD08  

Og efter adressen 0190BD08 snuble jeg lige over dette:

  .data: 0190BD08 unk_190BD08 db? ; ; DATA XREF: sub_40FFF0: loc_410049o.data: 0190BD08; sub_40FFF0: loc_410053o .... tekst: 00410049 loc_410049:; DATA XREF: .rdata: 01484034o.text: 00410049; .rdata: 0148489Co .... tekst: 00410049 mov ecx, offset unk_190BD08.text: 00410053.text: 00410053 loc_410053:; DATA XREF: .rdata: 01484078o.text: 00410053; .rdata: 01484C3Co .... tekst: 00410053 mov ecx, offset unk_190BD08  

Det ser ud som en blindgyde for mig ...

Jeg kan ikke se nogen referencer i din adskillelse til en statisk buffer. Hvor er henvisningen i demonteringen til det ækvivalente 's_CfgEntries'?
Nå, som jeg sagde, er jeg ikke rigtig ekspert i adskillelse, og koden, jeg skrev, er bare en pseudokode for at se, hvordan ASM kunne se ud i menneskelig læsbar kode. Jeg kan heller ikke se nogen statisk buffer, men metoden ReadCfgFile kaldes kun her: ".rdata: 0137A1EC dd offset ReadCfgFile", ".rdata: 0137A208 dd offset ReadCfgFile".
To svar:
sealed...
2014-05-08 09:39:25 UTC
view on stackexchange narkive permalink

Da jeg ikke kender prototypen af ​​ ReadCfgEntry og kodens struktur, er mit svar ikke nøjagtigt.

Først: Hvis bufferen er allokeret dynamisk

Da din funktion bruger ECX som initialiseret register:

  .text: 008F2886 mov esi, ecx  

Det er en klassefunktion, så ejerklassen har en konstruktør, der startede målbufferen. du skal spore bufferen og øge allokeringsstørrelsen.

Det er ikke en nøjagtig måde at finde konstruktør på; men en af ​​den effektive måde er at finde Virtuel funktionstabel

  • ved at spore ECX ved funktionsstart. oftest indeholder destinationsbufferen en VFT-enhed i det første element.

  • af XRef det i IDA (som du gjorde)

    ReadCfgFile kaldes kun her: ".rdata: 0137A1EC dd offset ReadCfgFile" ...

Efter at have fundet VFTable , det meste af tiden er konstruktøren det øverste medlem.

Andet: Hvis bufferen er statisk tildelt

Som jeg nævnte før, er funktionen medlem af klassen, så hvis du ændrer markøren af ​​interesse; det ville gøre arbejdet.

if (! ReadCfgEntry ((void *) (pointer + (996 * entriesCount) + 4), v5))

du skal indsætte en stub for at tildele korrekt hukommelse og tildele den til klassen.

ENDELIG: Hvis et program er lukket kilde, betyder det, at udvikleren ikke kan lide andre at ændre det til personlig brug ... være sikker på, at licensen ikke er overtrådt!

Jeg redigerer kun denne applikation til personlig brug, den vil ikke være harmløs, og jeg vil ikke offentliggøre disse ændringer offentligt ... det er bare en meget gammel applikation, der ikke mere er under udvikling, men det kan være virkelig, virkelig nyttigt for I mellemtiden redigerede jeg mit spørgsmål og tilføjede mine nylige fund, så sandsynligvis vil alt være klarere for dig nu.
Guntram Blohm supports Monica
2014-05-08 18:48:51 UTC
view on stackexchange narkive permalink

Det forekommer mig, at problemet er lidt værre, end du beskriver, og der er ingen nem måde at komme rundt på det.

For det første synes @sealed at være korrekt med funktionen som en klassemetode , og din kompilator passerer klassemarkøren i ecx , fordi det er den eneste måde for

  .text: 008F28B5 lea ecx, [esi + eax * 4 + 4] .text: 008F28B9 kalder ReadCfgEntry  

for at give mening - andre parametre skubbes på stakken, og værdierne for eax, edx og ebx synes ikke at være meget meningsfulde, så kompilatoren gør ikke ' t brug en slags parametre-i-registre fastcall abi.

Nu, lad mig omarrangere udsagnene fra loop-start til opkaldet lidt (uden at ændre betydningen, bare for at gøre lidt klarere, hvad der sker ). Compileren spredte instruktionerne "inkrement the count by one" mellem de andre, sandsynligvis for at drage fordel af pipelining i processoren:

  - få det aktuelle antal "antal config-poster" og afbryde sløjfen, hvis den overstiger 500.text: 008F2890 mov eax, [esi + 79954h] .text: 008F2896 cmp eax, 1F4h.text: 008F289B jge loc_8F29DF - forøg antallet af en. text: 008F28A6 lea ecx, [eax + 1] .text: 008F28AE mov [esi + 79954h], ecx-- eax = ((count << 5 - count) * 8) + count = count * 249.text: 008F28A1 mov edx, eax.text: 008F28A3 shl edx, 5.tekst: 008F28A9 sub edx, eax.text: 008F28AB lea eax, [eax + edx * 8] - push edi, som er en parameter til denne funktion, på stakken; - send dette = esi + 4 * eax +4 == esi + 996 * tælle + 4 i ecx. Husk, at esi blev indstillet til - `dette` = ʻecx 'i starten af ​​den aktuelle metode og ikke er blevet ændret..tekst: 008F28B4 push edi.text: 008F28B5 lea ecx, [esi + eax * 4 + 4] .text: 008F28B9 kald ReadCfgEntry  

Dette ser ud til, at ReadCfgEntry også er en klassemetode, der får sin denne -markør i cx. Fra den måde, som arrayindekset beregnes på, antager jeg, at den oprindelige C ++ -klasse så sådan ud:

  klassekonfiguration {int uanset; ConfigurationEntry poster [500]; ....}  

med ConfigurationEntry som en 996 byte klasse. Nu er den dårlige nyhed: Disse to klassemedlemmer har brug for 4+ (500 * 996) byte. Dette er lig med 498004 eller 0x79954. Så dit antal optagelser er direkte bag posterne ved 0x79954, med en anden variabel ved 0x79958:

  klassekonfiguration {int uanset; ConfigurationEntry poster [500]; int entryCount; int somethingelse; ... ??? ...}  

Hvis posterne nu havde været en markør og tildelt ny , ville det have været lettere at bare ændre størrelsesparameteren i den nye fra 500 til 1000. Men i dit tilfælde skal du ændre den nye metode i konfigurationsklassen, og du skal også ændre ALLE referencer til variabler "bag" konfigurationsindgangene. Du nævnte allerede det for tællingsvariablen ved forskydning 0x79954 og den næste variabel ved forskydning 0x79958, men der kan være flere af dem, der ikke bliver henvist til i din læserfunktion, så du har svært ved at finde dem alle.


Jeg var lige ved at sende dette, da jeg så din redigering af spørgsmålet.

Som du indså i din redigering, skal du ændre al adgang til strukturkomponenter bag den række af poster, du vil øge. Du skal gøre dette i dine klassemetoder (som du nemt kan finde, når du har vtabellerne), men også i resten af ​​dit program (da du ikke ved, hvilke af de oprindelige klassevariabler, der er offentlige og kan tilgås fra uden for selve klassen). Desværre kan du ikke rigtig automatisere det, for for enhver forekomst af f.eks. 0x79954 skal du kontrollere, om det er et indeks i din klasse eller noget andet.

Da jeg ikke ved, hvilken kompilator der blev brugt til at skrive dit program, kan jeg ikke fortælle meget om, hvordan den gemmer funktionen vtable. Med lidt held er den første post (den jeg kaldte uanset tidligere) vtable-markøren. Du kan kontrollere dette, hvis du kører programmet med en debugger, og kontrollere om variablen uanset peger på vtabellen, når den når ReadConfigFile-metoden. Hvis det gør det, er dette godt, fordi vi ikke behøver at bekymre os om at overskrive vtabellen, når vi udvider strukturen.

Så skal der være en tildelingsfunktion til dine klasser. Da du ser ud til at have en klasse kaldet DATABASE_TABLE og en afledt kaldet CFG_DB, er den anden sandsynligvis større. Prøv at finde initialiseringsmetoden til denne anden større klasse. Den skal kalde ny eller en lignende hukommelsesalloker med en størrelse, der passer til strukturstørrelsen (så den er sandsynligvis et sted mellem 79960h og 79a00h), og den skal flytte vtable-markøren ind i den nyligt tildelte hukommelse, så du kan muligvis finde det, der kontrollerer krydshenvisninger til vtabellen. Eller brug en debugger og indstil et breakpoint på ReadConfigFile, og kontroller stakken for, hvad der kaldte det, chancerne burde være gode, du finder en funktion, der tildeler klasseinstansen først og kalder derefter dens ReadConfigFile-medlemsfunktion.

Efter du finder ud af, hvor klassen er instantieret, vil jeg sandsynligvis forsøge ikke at øge arraystørrelsen fra 500 til 1000, men i stedet tildele en større array bag strukturen. For eksempel, hvis din aktuelle funktion tildeler 79a00h bytes, skal du tilføje de 996000d bytes, som 1000 poster har brug for, hvilket resulterer i 16cca0h bytes. Skift derefter

  lea ecx, [esi + eax * 4 + 4]  

foran ReadCfgEntry til

  lea ecx, [esi + eax * 4 + 16cca0h]  

På den måde har du oprettet en anden matrix bag den aktuelle struktur i stedet for at udvide den aktuelle. Hvilket betyder, at ingen af ​​dine strukturforskydninger, undtagen selve konfigurationselementerne, har ændret sig .

Når vi talte i C ++, ændrede vi bare klassen til

  klassekonfiguration {int uanset; ConfigurationEntry poster [500]; int entryCount; int somethingelse; ... ??? ... ConfigurationEntry newEntries [1000];}  

og i det næste trin skal vi omskrive alle adgang til poster for at bruge newentries .

Kontroller dine medlemsfunktioner for at få adgang til det originale array, og udskift dem også. Den mest enkle måde at gøre dette på er sandsynligvis

  • start programmet med en debugger
  • indstil et breakpoint på den funktion, du tidligere identificerede, der tildeler strukturen
  • efter at strukturen er tildelt, skal du indstille et hardwarepausepunkt til (strukturadresse + 4)
  • fortsæt programmet, og når du rammer hardwarepausepunkterne, fandt du et match

Da hardware-brudpunktet er på poster [0], er chancerne gode, at enhver adgang til en post rammer 0-det af det på et eller andet tidspunkt.

Også da ReadCfgEntry sandsynligvis er en klassemetode , chancerne er gode, at der er en sløjfe et eller andet sted, der bare tildeler en klasseinstans til hver post - noget som

  for (i = 0; i<500; i ++) {poster [i] = ny ConfigurationEntry ()}  

Dit hardwarepausepunkt skal fange denne løkke ret hurtigt. Patch den eksekverbare fil for at ændre 500 til 1000 og beregningen af ​​poster [i] til dit nye array. Derefter initialiseres dit nye array, men det gamle holder intet andet end NULL-markører. Hvilket betyder, at du muligvis får ugyldige hukommelsesadgang gennem disse NULL-markører i fremtiden, som også hjælper med at identificere adgang til dit originale array (som du kan patch).


Rediger - Rediger efter at have læst OP'er 2. svar

Uendelig? Slet ikke, du samlede og indsendte meget værdifulde oplysninger.

Først din pseudokode for CFG_DB-konstruktøren

  ugyldig __thiscall sub_8EEFC0 (ugyldig * dette) {void * v1 = dette; // esi @ 1 * (_ DWORD *) dette = &DATABASE_TABLE<CFG_ENTRY_500_unsigned_int> :: _ vftable_;  

bekræfter, at de 4 bytes i begyndelsen af ​​klassens funktion til den virtuelle klasse er den virtuelle funktion, klassen.

For det andet, dit uddrag

  .text: 008EE639 push ebp.text: 008EE63A lea ecx, [esp + 50h + var_2C] .text: 008EE63E push ecx .text: 008EE63F mov ecx, ebx.text: 008EE637 mov eax, [ebx] .text: 008EE641 kald dword ptr [eax + 14h] .text: 008EE644; -------------------------------------------------- ------------------------- .text: 008EE644 test al, al; HER ER STAKREFERENCEN  

passer meget godt. (Igen bestilte jeg monteringsvejledningen på en måde, der ikke ændrer, hvad de gør, men gør det tydeligere at forstå dem). Husk din vtabel, der havde en funktionsforskydning, en nullsub, yderligere 3 funktionsforskydninger og ReadCfgFile som dens poster? Da hver af disse har 4 byte, er forskydningen af ​​ReadCfgFile-funktionsmarkøren i vtabellen 20 eller 14 timer. I dette kodestykke er ebx en klassemarkør; mov eax, [ebx] får vtable-markøren fra klassemarkøren, og kald dword ptr [eax + 14h] kalder funktionen ved den forskydning, nemlig ReadCfgFile . Før det initialiserer det dette registeret (ecx) til ebx og skubber 2 parametre på stakken. Dette ser ud til at være et meget standardopkald til en klassemetode.

Derefter ender din konstruktør med

  unknown_libname_2673 ((char *) v1 + 4, 0x3E4u, 500, sub_8EEA00);  

hvor den første parameter (v1 + 4) er adressen til arrayet ConfigurationEntries inden for konfigurationsklassen (jeg holder mine gamle opfandt variabel / klassenavne), den anden parameter (0x3e4 == 996) størrelsen på hver matrixindgang; det tredje (500) antallet af poster og en tilbagekaldsfunktion. Jeg er næsten sikker på, at dette er konstruktorfunktionen til de enkelte ConfigurationEntries. Hvilket betyder, at dette er den funktion, jeg sagde, du skal finde, og som skal ændres til

  unknown_libname_2673 ((char *) v1 + XXXXX, 0x3E4u, 1000, sub_8EEA00);  

hvor XXXXX er forskydningen af ​​det nyeEntries-array, når vi allokerer plads til det.

Herefter genovervejer en del af kodestykket før det indirekte opkald til ReadConfigFile,

  .text: 008EE62A mov edx, [ebx] .text: 008EE62C mov ecx, ebx.text: 008EE62E mov [ebx + 7A938h], ebp.text: 008EE634 kald dword ptr [edx + 4]  kode> 

vi ser, at der er en bevægelse til ebx + 7A938h , hvor ebx er klassemarkøren, så der synes at være et andet klassemedlem ved denne forskydning. Dette er en hel del hukommelse efter forskydningen af ​​elementtællingen (79954h) - så strukturen har mange flere komponenter. God ting du ikke forsøger at flytte dem alle sammen. Konstruktorfunktionen, som får adgang til dette + 502036 , eller dette + 0x7a914 , ville have været et andet tip til det. (Den får også adgang til dette + 124503 , men da dette er en dword-markør, betyder det 498012 bytes, hvilket stadig er mindre end 502036).

Derefter fandt du ud af adressen 0190BD08, hvilket er en meget god ting. Sammen med XREF'erne og datadefinitionen

  .data: 0190BD08 unk_190BD08 db? 

dette betyder:

Klassestrukturen på den adresse tildeles IKKE dynamisk, og den initialiseres IKKE til noget, i stedet er den en ikke-initialiseret global variabel. I C ++ ville det sandsynligvis have været en

  statisk konfiguration myConfig;  

med alle de xrefs, du ser, er en henvisning til myConfig. Da monteringsvejledningen på disse steder er

  mov ecx, offset unk_190BD08  

Jeg er næsten sikker på, at opkaldene til en klassemedlemfunktion er en eller 2 instruktioner efter hver af disse. Tillykke, du har lige fundet en måde at fange mange af de tilfælde, hvor konfigurationen får adgang. For at bekræfte dette, hvis unk_190BD08 er en global variabel til konfigurationen, kan du køre programmet med et brydepunkt på konstruktorfunktionen (sub_8EEFC0), jeg vedder på, at det kun kaldes en gang, og 190BD08 er parameteren for det.

Den dårlige ting ved, at konfigurationsklasseinstansen er en statisk variabel, ikke en ny () - instantieret, er, at vi ikke bare kan øge størrelsen i det nye () opkald. I stedet bliver vi nødt til at flytte det til en del af adresseområdet, hvor det ikke forstyrrer noget andet - i slutningen af ​​det nuværende uinitialiserede datasegment. Find den allerførste post i dit datasegment, og vælg derefter en dejlig adresse bag det, og omskriv alle xrefs til unk_190BD08 til den nye adresse. Kør derefter programmet ved hjælp af ollydbg, placer et hardwarepausepunkt på 190BD08 bare i tilfælde, og kontroller at de funktioner, du ved, er klassemedlemsfunktioner, og de initialiserede, alle får den nye adresse i stedet for 190BD08 som deres ecx (denne) parameter. Når du er færdig, er du klar til at implementere 2. del, ændre adgangene til denne + 4 til denne + XXXX med XXXX er klassestørrelsen.

Det faktum, at vi mangler et nyt () opkald til konfigurationsvariablen, betyder, at vi ikke kan bruge dens parameter til at få klassestørrelsen. Men vi ved allerede, at klassestørrelsen er mindst 7A938h, så den statiske variabel optager adresseområdet fra 0x190BD08 til mindst 0x1986640. Med lidt held har dit .data-segment den unk_190BD08-label, hvor den næste label er på en adresse lidt efter 0x1986640, så den næste label er en anden variabel, og forskellen mellem begge labels er størrelsen på konfigurationsinstansen.

Der er én ting tilbage at gøre - når du flytter konfigurationsvariablen bag alt andet, bliver du også nødt til at øge størrelsen på det datasegment i PE-filen. Desværre er jeg ikke så dygtig i Windows PE-filformatet, så jeg bliver nødt til at undersøge meget, hvordan man selv gør dette korrekt, så måske er du heldig og en anden, der har mere erfaring i dette end Jeg har, kan hjælpe dig med dette.


Rediger - Rediger for at svare på kommentar

  • hvordan kan jeg beregne, hvor stor CFG_DB-klassen er for at tilføje noget i slutningen af ​​det?

Det oprindelige C ++ - program vil have haft noget som

  int somevariable; int someothervariable; CFG_DB globalConfig; int atthvarvariable;  

(int som et eksempel, datatypen kan være hvad som helst), og compileren skal placere alle disse variabler i den ikke-initialiserede del af .data-segmentet. Enhver adgang til en af ​​variablerne får IDA til at oprette en etiket på den hukommelsesadresse med en XREF, hvor den er adgang. Så hvis din .data dump ser sådan ud

  .data: 0190BD08 unk_190BD08 db? <-- sammen med nogle xrefs .data: 0190BD09 db? <-- dette gentages mange gange. Data:01986670 unk_1986670 db? <-- sammen med nogle xrefs  

og du ved, at 0190BD08 er din globalConfig , så er 01986670 athirdvariable , og størrelsen af ​​globalConfig er 0x01986670 - 0x0190BD08 = 0x7a968 = 502120 bytes.

Dette er ikke 100% idiotsikkert, for hvis noget får adgang til globalConfig.somemember, med somemember en strukturforskydning på f.eks. 500000 (= 0x7a120), så genererer IDA en label og en XREF ved 0x190BD08 + 0x7a120 = 0x1985E28 ass godt. Men med lidt held vil "resten" af programmet bare bruge globalConfig-variablen som et argument til en medlemsfunktion, hvor referencer er indirekte, så de vil ikke blive brugt af IDA til at oprette etiketter.

  • hvad sker der, hvis andre klasser / metoder / etc interagerer med denne ændrede klasse?

Hvis de får adgang til andet end de 500 individuelle konfigurationsindgange, slet intet, fordi disse har ikke ændret deres forskydning. Det, der kan være farligt, er når de får adgang til posterne, fordi disse adganger skal omskrives til newEntries. Du skal finde ud af, hvor de er (hvis du er heldig, det er bare i medlemsfunktionerne) og lappe koden på det tidspunkt. Hardwarepausepunktet på (gamle) poster [0] -adresse (hvilket er 0x190BD0C i dit tilfælde, strukturstart + 4) skal hjælpe med dette, fordi alt, hvad der sandsynligvis vil få adgang til enhver post, sandsynligvis også får adgang til post [0] . Så hvis du rammer hardwarepausen, siger, mov eax, [ebx + 4] , så ved du ebx + 4 har adgang til den gamle adresse og burde omskrives til mov eax, [ebx + XXXXX] for at bruge det nye array.

Desværre kan du ikke oprette et hardware-breakpoint, der dækker hele strukturen for at få adgang. Det er her, hvor undtagelserne med nul pointer sparker ind. Hvis dit program efter ændringen kaster en NPE, hvor det normalt ikke gør det, er det sandsynligvis fordi 'noget' har fået adgang til det gamle array, der ikke indeholder andet end NULL'er i stedet for det nye . At fange NPE i debuggeren og kontrollere den demontering / opkaldsstak, der fører til den, skulle give dig en idé om, hvor NULL-markøren blev læst fra det gamle array, så du ved, hvilken instruktion du skal ændre for at pege på den nye.

Tak for dit meget, meget værdifulde svar. Jeg redigerede mit svar med tilstandsoplysninger, der sandsynligvis kunne være nyttige for en, der er dygtigere end mig ...
Opdateret mit svar for også at svare på din 2. redigering.
@guntram jeg har ikke fordøjet svaret, men i dit forslag, hvis det er ok at tilføje plads i slutningen af ​​eksekverbar i stedet for i slutningen af ​​en eller anden sektion før en anden sektion, er det let, der er endda hjælpeprogrammer, der gør dette automatisk for dig og kan tilføje så meget plads, som du vil have i slutningen iirc santmants ZeroAdd er et sådant hjælpeprogram (været meget længe siden jeg brugte det, men skulle være tilgængeligt i woodmanns værktøjsudgave
Wow @GuntramBlohm, dit svar er bare fantastisk. Jeg ville aldrig have opdaget alt det uden din hjælp! Så for at genoptage en lille smule skal jeg: 1) flytte alle XRefs til unk_190BD08 til bunden af ​​mit datarum for at undgå overskrivning2) ændre 500 til 1000 og "v1 + 4" til den nye CFG_ENTRY [] adresse i unknown_libname_2673's kald i konstruktøren Men der er stadig to ting, jeg ikke forstår: hvordan kan jeg beregne, hvor stor er CFG_DB-klassen for at tilføje noget i slutningen af ​​det? Og ... hvad sker der, hvis andre klasser / metoder / etc interagerer med denne ændrede klasse?
Jeg har lige læst dit svar på min kommentar. Meget håndfuld og interessant som nogensinde. Min sidste tvivl, og jeg holder op med at chikanere dig, det lover jeg. Jeg forsøgte at beregne min CFG_DB størrelse, og jeg fandt dette: ".data: 0190BD08 CFG_DB" og derefter efter et par "?" linjer, ".data: 0190BD0C unk_190BD0C". Hvordan kan min CFG_DB-klasse kun have 4 byte i størrelse, hvis vi absolut ved, at den indeholder en int, 500 strukturer på 996 byte, og derefter en anden int? Skrabe mit hoved her ... måske er det bare en DWORD-markør til underklassen, der indeholder alle data, i hvilken casa det ikke ville være nødvendigt at flytte det til slutningen af ​​datasegmentet ...
Det ser ud til, at noget et eller andet sted har adgang til globalConfig.entries direkte. Dette får IDA til at sætte en etiket der sammen med en xref.


Denne spørgsmål og svar blev automatisk oversat fra det engelske sprog.Det originale indhold er tilgængeligt på stackexchange, som vi takker for den cc by-sa 3.0-licens, den distribueres under.
Loading...