Log in

View Full Version : More armadillo fun


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:

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 But I still haven't been able to get the screensaver dumped yet.

Thanks for the tute Crusader!

-nt20

_Servil_
November 27th, 2002, 19:25
hello,

got just a similar problem doing on the getright beta, also following crUsAdEr's step-by-step workaround, but found something fishy in 'decrypted' code section right when I was going to patch the breakpoints, noticed not at all the locations, referred by the i3 places table were breakpoints found (instead it some code, seeming make sense hwoever).

tried several changes -
-- changing the ArmaCryptDecrypt call directly to it's subsequent call to decrypt since there's a conditional jump that could possibly skip the main part (?)
-- making the loop infinite till crush (dump before confirming crash messagebox)
-- armkiller latest build
-- loop around 'ArmaCryptDecrypt' call located further in the exception_handler

the dump never matched all breakpoint places, since this is good indicator of fully decrypted section. given up at this point since i have no further idea.

crUsAdEr
November 27th, 2002, 23:10
Hi Nikola,

I have dumped both your menu test and the screen saver with no problem... which makes me wonder what is wrong? A few ppl already complain that they cant get things right...

What OS are you guys running? I doubt this is the problem but who knows... mine is win2k SP3...

The only reason i can think of is when you patch at offset 4477BD like this
inc dword ptr [ebp+section_number]
jmp up_to_loop

you reset the section number to zero before excuting the code above, so when you loop start, it will start with 1 instead and you fail to decrypt first block!!!! You have to reset section_number to 0 after the increment...

To see if each section are decrypted correctly, try tracing over the final call at 4477B5, try with the first few value of ecx, see if you trace over the call, if eax==1 then decryption is OK... if not then somethign is wrong...

That is all i can think of now...

Servil :
If you look at my Fix_Dump source code to fix int3, you will realise that not all address in the Table are inserted with and int3... so that is not a good indicator if your dump is not OK.

cheers
crUsAdEr

crUsAdEr
November 27th, 2002, 23:23
Found your bug Nikola,

You patch the AMountOfSection to 1000 which is wrong, yo should not do that... because that is the limit for your decryption loop... in my tutorial when i said patch the Max number of decrypted block, i mean patch the value at dword_46067C which is referred to at instruction "text1:004488A0" of your code snippet instead of patching the jle... this is when armadillo check if max number of decrypted block allowed, which is half of total number of blocks...

So try that, hopefully it should work now...

Cheers
crUsAdEr

nikolatesla20
November 27th, 2002, 23:57
Thankx for looking at it crusader, HAH ya I didnt even think to look to make sure I clear to zero after I execute my newly inserted instruction.

HMM. I will keep looking. Just for a little nugget - does the screensaver contain the Int3's?


At work I am running Win2K SP3 , at home XP pro SP1.

-nt20

nikolatesla20
November 28th, 2002, 00:23
Ok thank you crusader, I got the screensaver dumped now. Just have to start building it IAT table. (didnt go thru that whole part yet).

As a side note, as usual the registration check is even simpler now that it relies on ArmAccess.dll

-nt20

crUsAdEr
November 28th, 2002, 00:37
Cool Nikola :>

I did not check if it has int3 features so i am not sure abt that.. now you have a good dump then you can check it out yourself ... after rebuilding IAT could you help me test the armadillo plug in i posted in TOT forum? in WIn XP esp. see if it works.. i really want to learn how to code OS-independent code but very few ppl replied whether the plug in works :<... h well, if u have the time....

Cheers
crUsAdEr

nikolatesla20
November 28th, 2002, 06:13
Thanks again for the help, Crusader.

After I got the screensaver dumped correctly, I rebuilt the IAT using ImportREC (even though I prefer Revirgin). Revirgin , even when I would enter the IAT start address, just wouldn't even start to resolve.

I used ImportREC with your plugin and it worked great. Here was my own method for resolving the IAT:

I first disassemble the dumped file after correcting the OEP, the symbol table pointer bad values, and the code and data start values. This gives me a disassembly to find a CALL DWORD PTR [xxxxxxxx] call, which would be an API.

Then I started the packed file, thinking that even though armadillo does copymem, the original IAT HAS to be present for the program to run at all. I mean at least the addresses have to be in memory and available. So in SI I got the the [xxxxxxxx] address and sure enough there are the values. Scroll up and down to get the start and length values.

Put these into ImportREC and press "Get Imports". You get a few invalids. Use your plugin on them, and wallah, perfection.

I've now removed the further flaws such as time checks, and its running great - WinXP Pro SP1.

Thanks for the help on *rmadillo, in my opinion this program is harder in some ways then *SProtect. But easier in the fact that you can disassemble a file protected with it to see how the protection works!

-nt20

crUsAdEr
November 28th, 2002, 09:22
Hi Nikola,

Yep, thanx for the replay.. here is how i do it normally... start with bpx SetProcessWorkingSetSize then find call edi, note down value of edi (OEP), then immediately bpx WriteProcessMemory and do the decrypt until infinite loop... there i make a full dump, fire up Imprec and enter the OEP, Imprec will automatically search for IAT for you without fail, then "Get Import", then SHowInvalid... it works because after you force armadillo to fully decrypt your file, and suspend then... Imprec will be able to run through the whole program code and find IAT for you...

Just a final thought,
Cheers
crUsAdEr

nikolatesla20
November 28th, 2002, 14:02
Yes, very good method, which I was going to use except for 2 small things:

1. Once the hacked armadillo process locks up, it literally eats my CPU. I have to get into task manager and right click on it and lower its priority. It does this on both Win2K and XP. So, it takes a little while to do this because the thread seems to just eat cycles, even though it's default priority. It does this with any armadillo program I've forced a decrypt on. The dump works fine tho.

2. I had already dumped the SS, and forgot about trying to resolve. Otherwise, yes, the best time is to do it while the process is suspended. But my computer was actually blue screening (XP yikes!) for some reason and I wanted to minimize the damage, so I shyed away from hacking the process again. Incidentally, I don't like how SoftICE changes your file itself when you change opcodes. I have to keep a backup of the file for each time after testing the forced decrypt, if it didn't work.

Anyway, it's good to know that there is another way to resolve the IAT just using the normal protected program as well. ImpREC works for that but Revirgin doesn't . Revirgin should work on a suspended process, however.

-nt20

Mega Desperate
November 30th, 2002, 03:36
Quote:
Originally posted by crUsAdEr
Hi Nikola,

Yep, thanx for the replay.. here is how i do it normally... start with bpx SetProcessWorkingSetSize then find call edi, note down value of edi (OEP), then immediately bpx WriteProcessMemory and do the decrypt until infinite loop... there i make a full dump, fire up Imprec and enter the OEP, Imprec will automatically search for IAT for you without fail, then "Get Import", then SHowInvalid... it works because after you force armadillo to fully decrypt your file, and suspend then... Imprec will be able to run through the whole program code and find IAT for you...

Just a final thought,
Cheers
crUsAdEr


Hi..!! =-P ... i have dump file.. but i not understand.. why ImpRC & Revirgin they say to me ..that the IAT is all correct.. =-|..

I dump correctly?¡ .. i did this.


Put bpx setprocessworkingsetsize ... go to CALL EDI ..now bpx writeprocessmemory .. i push F12 two times .. i now here:


005DF9DC 83 C4 0C add esp, 0Ch <== I LAND HERE!
005DF9DF 25 FF 00 00 00 and eax, 0FFh <--edit here
005DF9E4 85 C0 test eax, eax
005DF9E6 74 0A jz short bad_jump

push F10 ...

now put

a eip
inc dword ptr [ebp+FFFFFA18]
jmp 5DF92D

005DF92D 8B 8D 2C FA FF FF mov ecx, [ebp+FFFFFA18]
005DF933 3B 0D 84 9A 45 00 cmp ecx, ds:text_section_size
005DF939 0F 8D C7 00 00 00 jge continue_1

5DF939 <-- here put "JMP EIP"


now go to LordPE ... and dump full ...

it's correct my dump? ... and If I am in the correct thing .. Please!! ...say to me since I reconstruct the IAT?¡ -.. .

I read other topic ...

"..I used ImportREC with your plugin and it worked great.."

u can to provide this plugin?¡ ---






thank u =-D

r4g3
November 30th, 2002, 15:27
"Mega Desperate" ? ... doesn`t that leed to a suicide, sooner or later ?

nikolatesla20
November 30th, 2002, 19:26
MegaDesperate,

Make sure you select the correct process when you try to rebuild the imports. YES the dumped file will have a good IAT , but it is NOT THE RIGHT ONE. It's an IAT put there by Armadillo.

For the plugin, search the unpacking forum (search button) for "armadillo plugin" and you will find the thread with the link.

BTW I still get small crashes every so often with the screensaver, I used SI and found it was a crash in opengl, in the texture coords calls. The screensaver does not use the int 3 trick ( I bpint 3 and it never comes up), but I clearly get a bad pointer now and then. Could just be a program bug, but I haven't investigated further. I think I'm done with this for now.

-nt20