nikolatesla20
November 27th, 2002, 18:20
I've been going thru Crusader's tutorial, but I'm still having some problems getting all my pages loaded. Let me explain.
I downloaded the latest armadillo. Its version 2.65 now. I wrapped a generic windows program that I made in MFC with armadillo, using copymem II plus debug blocker, medium compression, simple softICE detection. I am trying to unpack it now. I am using Win2K / XP with DriverStudio 2.7.
Ok.
First I load the sucker into IDA. The armadillo "server" is actually a debugger. The debugger loop sits and watches for errors, such as page faults. Of course we will get a page fault right away when the program loads because armadillo sets up the pages to "PAGE_NO_ACCESS". We can disassemble the protected file and see what is going on.
It's easy to trace thru the code (especially with IDA) to see the check for a PAGE_FAULT. Here is a piece of it:
So, at the end of that, we have a jump to the decypting routines.
Here's the decrypting routine:
Yep, same as Crusader has pointed out before. No big deal here. We just change the JGE at 00447703 to an infinite loop, then we clear [ebp+SectionNumber] to zero, and we set AmountOfSections to a nice big number (like 1000h), and finally we edit the code to increment the SectionNumber and loop to 004476F7. I added this code at location 004477BD, right AFTER the "add esp, 0Ch" code. Maybe this was not good. Crusader's tute said to put it right at that point. Maybe this is what is causing my problem?
Anyway, the last piece of code to patch in memory: This is the actual decrypt routine that gets called. we want to always decrypt.
So we patch that jump at 004488A6 so it always jumps, just like the tutorial.
The final result I get if I look at the process in S.I. is weird. Not only did I not get all of the sections (I'm only missing a couple), but in most places, only ever - other - section is actually decoded. I mean the section is present and readable, but it's filled with zeros. So that's the main problem I'm having. I still cant dump it yet with LordPE because apparently a couple of pages are still missing.
By the way, yes I am trying to learn how to do this manually, so if you do have an unpacker, feel free to mention it, but dont beat me in the head with it!
You can get the protected file I made from here:
http://webpages.charter.net/nikolatesla20/testmenu.zip
To try it out yourself.
If you want a real life challenge that uses Armadillo, you can try out Beam Screensaver, which got me into this.
http://beamscreensaver.com
Anyway, it's weird, I think I just got my program to dump now, but I'm still not sure why - sometimes it seems to work better than others
But I still haven't been able to get the screensaver dumped yet.
Thanks for the tute Crusader!
-nt20
I downloaded the latest armadillo. Its version 2.65 now. I wrapped a generic windows program that I made in MFC with armadillo, using copymem II plus debug blocker, medium compression, simple softICE detection. I am trying to unpack it now. I am using Win2K / XP with DriverStudio 2.7.
Ok.
First I load the sucker into IDA. The armadillo "server" is actually a debugger. The debugger loop sits and watches for errors, such as page faults. Of course we will get a page fault right away when the program loads because armadillo sets up the pages to "PAGE_NO_ACCESS". We can disassemble the protected file and see what is going on.
It's easy to trace thru the code (especially with IDA) to see the check for a PAGE_FAULT. Here is a piece of it:
Code:
.text1:00447522 mov ecx, [ebp+lpDebugEvent]
.text1:00447528 mov edx, ds:lpProcessInformation
.text1:0044752E mov eax, [ecx+4] ; Check process ID is correct
.text1:00447531 cmp eax, [edx+8]
.text1:00447534 jnz loc_44869B
.text1:0044753A mov [ebp+dwContinueStatus], 80010001h
.text1:00447544 mov ecx, [ebp+lpDebugEvent]
.text1:0044754A cmp dword ptr [ecx], 1 ; Debug Event code : EXCEPTION_DEBUG_EVENT
.text1:0044754D jnz loc_447EF9
.text1:00447553 xor edx, edx
.text1:00447555 mov dl, ds:byte_463A7C
.text1:0044755B test edx, edx
.text1:0044755D jz loc_4477D5
.text1:00447563 mov eax, [ebp+lpDebugEvent]
.text1:00447569 cmp dword ptr [eax+0Ch], 80000001h ; EXCEPTION_GUARD_PAGE
.text1:00447570 jnz loc_4477D5
.text1:00447576 mov ecx, [ebp+lpDebugEvent] ; GOES HERE IF PAGE_FAULT
.text1:0044757C mov edx, [ecx+24h]
.text1:0044757F mov [ebp+ExceptionAddress], edx
.text1:00447585 mov eax, [ebp+lpDebugEvent]
.text1:0044758B mov ecx, [eax+18h]
.text1:0044758E mov [ebp+AddressAgain], ecx
.text1:00447594 mov edx, [ebp+lpDebugEvent]
.text1:0044759A xor eax, eax
.text1:0044759C cmp dword ptr [edx+20h], 0
.text1:004475A0 setz al
.text1:004475A3 mov [ebp+var_5D0], al
.text1:004475A9 mov ecx, [ebp+ExceptionAddress]
.text1:004475AF sub ecx, ds:dword_463A8C ; Subtract the image base
.text1:004475B5 shr ecx, 0Ch
.text1:004475B8 mov [ebp+SectionNumber], ecx
.text1:004475BE xor edx, edx
.text1:004475C0 mov dl, ds:byte_463A7D
.text1:004475C6 test edx, edx
.text1:004475C8 jz loc_4476EA ; This will usually jump here - think it jumps if to decrypt
So, at the end of that, we have a jump to the decypting routines.
Here's the decrypting routine:
Code:
.text1:004476EA cmp [ebp+SectionNumber], 0
.text1:004476F1 jl loc_4477D0
.text1:004476F7 mov ecx, [ebp+SectionNumber] <- Loop back to this point
.text1:004476FD cmp ecx, ds:AmountOfSections
.text1:00447703 jge loc_4477D0 ; If its above amount of sections, go to next set of checks.
.text1:00447709 mov edx, [ebp+var_564]
.text1:0044770F and edx, 0FFh
.text1:00447715 test edx, edx
.text1:00447717 jz loc_4477C6
.text1:0044771D push 0
.text1:0044771F mov esi, [ebp+SectionNumber]
.text1:00447725 shl esi, 4
.text1:00447728 mov eax, [ebp+SectionNumber]
.text1:0044772E and eax, 80000007h
.text1:00447733 jns short loc_44773A
.text1:00447735 dec eax
.text1:00447736 or eax, 0FFFFFFF8h
.text1:00447739 inc eax
.text1:0044773A
.text1:0044773A loc_44773A: ; CODE XREF: sub_44665D+10D6j
.text1:0044773A xor ecx, ecx
.text1:0044773C mov cl, byte ptr ds:unk_4631F0[eax]
.text1:00447742 mov edx, [ebp+SectionNumber]
.text1:00447748 and edx, 80000007h
.text1:0044774E jns short loc_447755
.text1:00447750 dec edx
.text1:00447751 or edx, 0FFFFFFF8h
.text1:00447754 inc edx
.text1:00447755
.text1:00447755 loc_447755: ; CODE XREF: sub_44665D+10F1j
.text1:00447755 xor eax, eax
.text1:00447757 mov al, byte ptr ds:unk_4631F1[edx]
.text1:0044775D mov edi, ds:dword_460238[ecx*4]
.text1:00447764 xor edi, ds:dword_460238[eax*4]
.text1:0044776B mov ecx, [ebp+SectionNumber]
.text1:00447771 and ecx, 80000007h
.text1:00447777 jns short loc_44777E
.text1:00447779 dec ecx
.text1:0044777A or ecx, 0FFFFFFF8h
.text1:0044777D inc ecx
.text1:0044777E
.text1:0044777E loc_44777E: ; CODE XREF: sub_44665D+111Aj
.text1:0044777E xor edx, edx
.text1:00447780 mov dl, byte ptr ds:unk_4631F2[ecx]
.text1:00447786 xor edi, ds:dword_460238[edx*4]
.text1:0044778D mov eax, [ebp+SectionNumber]
.text1:00447793 cdq
.text1:00447794 mov ecx, 1Ch
.text1:00447799 idiv ecx
.text1:0044779B mov ecx, edx
.text1:0044779D shr edi, cl
.text1:0044779F and edi, 0Fh
.text1:004477A2 add esi, edi
.text1:004477A4 mov edx, ds:dword_463A84
.text1:004477AA lea eax, [edx+esi*4]
.text1:004477AD push eax
.text1:004477AE mov ecx, [ebp+SectionNumber]
.text1:004477B4 push ecx
.text1:004477B5 call sub_44870A ; Call ArmaCryptDecrypt
.text1:004477BA add esp, 0Ch
.text1:004477BD and eax, 0FFh <--- I inserted my code starting here
.text1:004477C2 test eax, eax
.text1:004477C4 jz short loc_4477D0 ; Want to loop here to decrypt all sections (increment section count first)
Yep, same as Crusader has pointed out before. No big deal here. We just change the JGE at 00447703 to an infinite loop, then we clear [ebp+SectionNumber] to zero, and we set AmountOfSections to a nice big number (like 1000h), and finally we edit the code to increment the SectionNumber and loop to 004476F7. I added this code at location 004477BD, right AFTER the "add esp, 0Ch" code. Maybe this was not good. Crusader's tute said to put it right at that point. Maybe this is what is causing my problem?
Anyway, the last piece of code to patch in memory: This is the actual decrypt routine that gets called. we want to always decrypt.
Code:
.text1:0044889A
.text1:0044889A loc_44889A: ; CODE XREF: sub_44870A+297j
.text1:0044889A mov edx, ds:dword_463A98
.text1:004488A0 cmp edx, ds:dword_46067C
.text1:004488A6 jle loc_4489A6 ; patch this right here
.text1:004488AC mov eax, ds:dword_463A98
.text1:004488B1 sub eax, 1
.text1:004488B4 mov ds:dword_463A98, eax
So we patch that jump at 004488A6 so it always jumps, just like the tutorial.
The final result I get if I look at the process in S.I. is weird. Not only did I not get all of the sections (I'm only missing a couple), but in most places, only ever - other - section is actually decoded. I mean the section is present and readable, but it's filled with zeros. So that's the main problem I'm having. I still cant dump it yet with LordPE because apparently a couple of pages are still missing.
By the way, yes I am trying to learn how to do this manually, so if you do have an unpacker, feel free to mention it, but dont beat me in the head with it!

You can get the protected file I made from here:
http://webpages.charter.net/nikolatesla20/testmenu.zip
To try it out yourself.
If you want a real life challenge that uses Armadillo, you can try out Beam Screensaver, which got me into this.
http://beamscreensaver.com
Anyway, it's weird, I think I just got my program to dump now, but I'm still not sure why - sometimes it seems to work better than others

Thanks for the tute Crusader!
-nt20