Log in

View Full Version : Help with a weird encrypter/packer


hobferret
May 30th, 2004, 16:52
Hi all

I have gotten hold of a program that won't run with any sort of debugger/dissembler

It has 5 sections
.text
.rdata
.data
.rsrc
.perplex

It only gives you 3 runs and then you gotta reg it, not very friendly

I have searched the web and exetools and this forum and only found one mention of it and that did not tell me anything

Does anyone know of this and how to defeat it

Regards

/hobferret

Js
May 30th, 2004, 18:20
only protector I have seen with that section name is Ultra/aCprotect but unless its been much improved the no debug doesn't sound right. would you please pm me the target?

cRk
May 30th, 2004, 19:06
would you give more detail info. about it????

you're not too newbie for this kind of posts ... at least mention the target so we can search for it.

Regards

nikolatesla20
May 30th, 2004, 23:47
Yep, that's ACProtect..

Nothing too hard here, just attack it as usual...hide your debugger with the usual FS[0] byte editing trick in Olly, or use an Olly debug hider plugin, search the board for more info about these.

ACProtect uses the CreateToolhelp32 API to detect a parent process that is running it, to make sure it's not being run under a debugger. You can bp on this API and for the CreateToolHelp32 call to return a zero (FAIL).

Not sure which ACProtect it is, 1.09 replaces various CALL instructions in the target to upper memory locations, it's easy to recover these though since they are listed in a sequential table, just find the first one, and you can auto-patch all the rest

I made a scanner for these, based on this method..

Look for "E8" byte first (CALL)
if found, grab next four bytes, if they are higher than BASE+SIZE ignore them
if they are higher than OEP then calc where they go to by getting next address (current address +5) and adding...DWORD should always be positive since new call exists in higher memory...

Code:

// Fixes ripped code segments in a dumped file - here it scans
// a file in memory, and fixes the segments from the process
// this is currently running.

BOOL FixRippedCodeMemory(HANDLE hProcess,LPVOID lpMem)
{

LPVOID lpBase = lpMem;
LPVOID OriglpMem = lpMem;

unsigned char* Byte;
DWORD* CallData;
DWORD JumpAddress;
DWORD AddressOfOrigCode;
DWORD Distance;
DWORD LastValidAddress;

// Scan for CALLS that are above mem space

// need to calculate the difference between our mapped mem
// and the file's imagebase
/*
if ((DWORD)lpMem > MemImageBase)
MemDifference = ((DWORD)lpMem - MemImageBase);

if ((DWORD)lpMem < MemImageBase)
MemDifference = (MemImageBase - (DWORD)lpMem);
*/

// Scanner. MemSize if relative
for (unsigned long i = (DWORD)lpBase; i < (DWORD)lpBase + LastSectionVA;i++)
{

// Look for "E8" byte first (CALL)
// if found, grab next four bytes. if they are higher than BASE+SIZE ignore them.
// if they are higher than MemMatchLow then Calc where they go to
// by getting next address (current address + 5) and adding..
// DWORD to call should always be positive, it exists in higher memory.
Byte = (unsigned char*)lpMem;

if (*Byte == 0xE8)
{

// read next 4 bytes (DWORD) , see it it's a valid address
CallData = (DWORD*)((DWORD)lpMem + 1);

if (*CallData != 0)
{


// calculate the distance from the next instruction.

Distance = (((DWORD)lpMem+5) + ((DWORD)*CallData) - (DWORD)lpBase);

Distance = Distance + (DWORD)PEImageBase;

if ((Distance > (PEImageBase+LastSectionVA)) && (Distance < (PEImageBase + PEImageSize)))
{

// this is a valid CALL instruction into higher memory.
//printf("CallData: %Xh \n",*CallData);
//printf("Address: %Xh \n",(DWORD)lpMem - (DWORD)lpBase);

LastValidAddress = Distance;
//ClearMessage();
//sprintf(MESSAGE,"CALL found to: %Xh ",Distance);
//ShowMessage();

// grab the value of the JMP from this call.
// first, make sure it's a JMP instruction
// REMEMBER, lpMEM still points to the original CALL instruction
// look at the bytes at "Distance"

// convert back to our file mapping postion
Distance = Distance - (DWORD)PEImageBase;

Distance = Distance + (DWORD)lpBase;

//printf("Distance new is %Xh \n",Distance);

ZeroMemory(&JumpData,sizeof(JumpData));

memcpy(&JumpData,(void*)Distance,2);

if (memcmp(JumpData,JMP_INSTRUCT,2)==0)
{

// this is a valid JMP
//printf("JMP Valid ";

// get the JMP [<address>]
memcpy(&JumpAddress,(void*)(Distance+2),sizeof(DWORD));

ClearMessage();
sprintf(MESSAGE,"CALL Found at: %Xh - JMP Valid, address Found: %Xh",LastValidAddress,JumpAddress);
ShowMessage();


//printf("Address found: %Xh \n",JumpAddress);

// now we would read in the value from that address, from the
// other process space, move to that value, and grab five bytes
// and replace the original CALL instruction with the original bytes
ZeroMemory(&ORIG_CODE,sizeof(ORIG_CODE));

if (ReadProcessMemory(hProcess,(LPVOID)JumpAddress,&AddressOfOrigCode,sizeof(DWORD),NULL)==0)
{
ClearMessage();
printf("Couldn't read process mem to patch Code: Error: %d \n",GetLastError());
ShowMessage();

return FALSE;
}

// read the five bytes, and copy them
ReadProcessMemory(hProcess,(LPVOID)AddressOfOrigCode,ORIG_CODE,5,NULL);

// copy the original bytes back.
memcpy(lpMem,ORIG_CODE,5);


}

//break;

}


}


}

// move lpBase
lpMem = (LPVOID)((DWORD)lpMem + sizeof(unsigned char));

}

lpMem = OriglpMem;

return TRUE;
}




Attachment for version 1.09f. New version is different now though..

-nt20

hobferret
May 31st, 2004, 04:34
Thankx everyone for your replies

Will first of all try nt20's method

Can't post target names or will be flamed by admin

Regards

/hobferret

Shoob
June 1st, 2004, 17:34
Is this this same as the old FixACDump Proggy? i loved it btw great innovative Smilies props go to admin!

sna
June 2nd, 2004, 18:31
Hi.

Nikola's method for dealing with the anti-dumping protection will unfortunately not work past version 1.09. During protection of a file, sets of instructions that occupy 5 bytes are processed in a poly-engine that makes sure any derived set take up more than 5 bytes. The new sets are stored in an array that is put with the other project dependent data in the ACProtect appended section.

During protector initialization, just after decompressing the sections, you'll see how it moves the array into dynamically allocated memory. A bit later on it will iterate over a second array, containing offsets (?) to the original instruction sets and overwrite them with CALL instructions to link in the new code instead.

Question, if you were a building engineer and you had to repair a house... Would you wait until it came down in pieces to only then pick them up and try to repair whatever damage there was in the first place?

Regards, sna

Kayaker
June 2nd, 2004, 19:27
Hi

>>During protection of a file, sets of instructions that occupy 5 bytes are processed in a poly-engine that makes sure any derived set take up more than 5 bytes.

>>Question, if you were a building engineer...


Clever modification.

Yes, but you don't put an umbrella up before it rains either . Ahh, when you own a house you're always renovating, building additions, moving the furniture around, putting fluffy pillows on the couch..., same as in programming. I think the protector side enjoy/hate the challenge of having to write better programming code, as much as the other side does to tear it apart, only with a more vested interest

K.

nikolatesla20
June 2nd, 2004, 22:56
Quote:
[Originally Posted by sna]Hi.

Nikola's method for dealing with the anti-dumping protection will unfortunately not work past version 1.09. During protection of a file, sets of instructions that occupy 5 bytes are processed in a poly-engine that makes sure any derived set take up more than 5 bytes. The new sets are stored in an array that is put with the other project dependent data in the ACProtect appended section.

During protector initialization, just after decompressing the sections, you'll see how it moves the array into dynamically allocated memory. A bit later on it will iterate over a second array, containing offsets (?) to the original instruction sets and overwrite them with CALL instructions to link in the new code instead.

Question, if you were a building engineer and you had to repair a house... Would you wait until it came down in pieces to only then pick them up and try to repair whatever damage there was in the first place?

Regards, sna



I have not examined in detail the new version, but the principles are the same, all you need to do is look for CALLS that are outside the original program's memory space. That's the problem with protectors, they must use higher mem. Once you have those, now it's easy to pick and choose the code you want to rip. A protector is not the only one that can write a "poly engine" (which is just a buzzword). Frequently these "poly engines" contain logic errors and still have a basic pattern than can be searched for. Think outside the box (or in this case, outside the EXE).

-nt20

cRk
June 3rd, 2004, 10:21
anyone knows what anti-loader tricks this program use?? which API use to know that the exe is been running from other exe .. actually a loader ..also Regmonitor does not work ..i mean the Acprotect exe as it detect it just crash .. same as any loader .. it crash before Writeprocess memory happends so it knows that it's been ran with other process or exe (loader)
i managed to dump it and knows where the OEP should be but has most bytes at the begin stolen or encrypted .. IAT almost completed but for kernel32 and other API all entries all missing

nikolatesla20
June 3rd, 2004, 12:08
Take a look at this thread

http://www.woodmann.net/forum/showthread.php?t=4900&highlight=acprotect

shows what the program searches for. It uses the ToolHelp32 API to find running processes, etc. Part of the TOolhelp API you can use to find a parent process, so it can see what process is its parent.

You can bypass everything by forcing CreateToolhelp32Snapshot API to fail (return a zero in EAX), since this protection must still work on Win9X, and this API might not exist, it then continues on without any ill effects (because it has to be prepared for the API not being installed, and then it can't use it).


-nt20

hobferret
June 6th, 2004, 10:26
Hi all

I have been messing around with this for a while now and am still PERPLEXED

The only place where I can find the memory being modified is at an instruction MOV BYTE PTR DS:[EDI],AL where it puts as nt20 says E80B000000 at 00401000, I try to put a breakpoint on memory access or execution but the program crashes prior to getting there.

Loads of unable to pass exception to program. :!:

Any body have any ideas?

Regards

/hobferret