Exetools  

Go Back   Exetools > General > General Discussion

Notices

Reply
 
Thread Tools Display Modes
  #16  
Old 08-03-2012, 01:46
RedBlkJck RedBlkJck is offline
Family
 
Join Date: Oct 2011
Posts: 99
Rept. Given: 64
Rept. Rcvd 80 Times in 43 Posts
Thanks Given: 25
Thanks Rcvd at 11 Times in 9 Posts
RedBlkJck Reputation: 80
@axl936
AFAIK registration at tuts4you is open. Unpacking different targets are well covered there. The post was a little long with having to solve a problem with olly setup, etc. Here is a shortened version of what I posted with some selective editing.


mpress is easy to unpack as there is very little to prevent unpacking. There is a generic pattern that can be used RET JMP, step, POPAD JMP = OEP There are olly scripts that will do this. Load the packed file in Olly. Scroll down in Olly until the code goes to all null bytes, scroll back up and you will see RET followed by JMP C3E9. Break on JMP and run. Step in after break. Scroll down in Olly again looking for the POPAD followed by JMP 61E9. Break on JMP and run. The JMP destination is your OEP. Step once and you are at OEP. Dump and rebuild your taget. It should run but this app is compiled with MS VC++ and uses floating point literal constants. Your dump will have a R6002 error msg.

The problem of R6002 error can be seen across other packers also. If UPX was used to pack the same file and you dumped it, the same error would occur in your dump. Just like Mpress your dump would have all the sections placed into the first section .UPX0 If you used UPX -d flag or a program like PE Explorer the unpacked UPX file would not have the error. This is because a copy of the original PE would be used to rebuild it back to the origial sections. Mpress doesn't include this so you would have to rebuild the original sections manualy.

This blog posting covers the problem of MSVC++ floating point that packers will have to deal with. It has an example not packed to demostrate the problem and how to track it. Read this to get an understanding of the R6002.
http://nezumi-lab.org/blog/?p=73

Ghandi posted some more indepth details on the tuts4you thread with other code list examples. I'm only quoting a small portion of ghandi's post.
Quote Ghandi
But it is sufficient to say that the following check is performed and if the call to IsNonWiteableInCurrentImage returns FALSE, it will throw that error. The fix is simple when the sections haven't been mangled, just change the permissions of '.rdata' to read only and if the sections have been mangled you can always patch the code itself to bypass this check.
PHP Code:
013E30C1                391D A8573E01    cmp dword ptr [__dyn_tls_init_callback],ebx
013E30C7                74 19                    je short 013E30E2
013E30C9                68 A8573E01        push offset __dyn_tls_init_callback
013E30CE                E8 BD040000        call _IsNonwritableInCurrentImage
013E30D3                59                              pop ecx
013E30D4                85C0                      test eax
,eax
013E30D6                74 0A                    je short 013E30E2 
For a better understanding of what was going on, I used the example of r6002 bug from that blog posting and packed it with Mpress 2.17. Attached below with the original source.


Mpress takes all the sections and places them into one, the resource mappings are kept in their own section but the raw resources are placed into mpress1 section. .mpress2 section is packer code. If you change permissions to read only on .mpress1 of your dump, you are changing it for all the original sections and the app will crash with different error. The packer is dealing with the same problem of the rdata section, this is why the app doesn't crash while packed.

Basically a section of the file PE header will be read and checked for what permission attributes it has. It does not verify the permissions of the section as it is actually loaded in memory, just the PE. If the attributes of the section is read only then EAX = 00000001 on the RET to the call. When TEST EAX, EAX is performed, the next conditional jump JE SHORT will not jump. If EAX = 00000000 JE SHORT will JMP causing the R6002 msg. You can see this in the same code above from Ghandi @013E30D6. In testing with other examples of this, the result is the same.

So how you patch it is up to you. Just so the call causing the error msg is not the next instruction at JE SHORT. Using the packed demo and the break point method from the blog, I added some observation notes. Follow the same method with your Gearotic target and you will come to the same solution.

PHP Code:
0040719E        PUSH r6002dum.0041D680
004071A3        CALL r6002dum.0040E780

0040E780        MOV EDI
EDI
0040E782        PUSH EBP
......
......
0040E7D5        PUSH EAX
0040E7D6        PUSH r6002dum.00400000                  
Image base
0040E7DB        CALL 
<r6002dum.ReadThePESections>       ;0040E730

0040E730        MOV EDI
EDI                            ;<ReadThePESections>
0040E732        PUSH EBP
0040E733        MOV EBP
ESP
0040E735        MOV EAX
DWORD PTR [EBP+8]              ; Stack SS:[0018FF0C]=00400000
0040E738        MOV ECX
DWORD PTR [EAX+3C              0040003C Offset to PE signature
0040E73B        ADD ECX
EAX                            ; [00400054]
0040E73D        MOVZX EAXWORD PTR [ECX+14]            ; 00400054 SizeOfOptionalHeader E0 (224.)
0040E741        PUSH EBX
0040E742        PUSH ESI                                
; [00400046]
0040E743        MOVZX ESIWORD PTR [ECX+6]             ; 00400046 NumberOfSections 4
0040E747        
XOR EDXEDX
0040E749        PUSH EDI
0040E74A        LEA EAX
DWORD PTR [EAX+ECX+18]         ; 00400138 Address=00400138, (ASCII ".MPRESS1")
0040E74E        TEST ESIESI
0040E750        JBE SHORT r6002dum.0040E76D
0040E752        MOV EDI
DWORD PTR [EBP+C]
0040E755        MOV ECXDWORD PTR [EAX+C]              ; 00400144 VirtualAddress 1000
0040E758        CMP EDI
ECX
0040E75A        JB SHORT r6002dum.0040E765
0040E75C        MOV EBX
DWORD PTR [EAX+8]              ; 00400140 VirtualSize 26000 (155648.)
0040E75F        ADD EBXECX                            ECX=00001000 EBX=00026000
....
....
0040E772        POP EBP
0040E773        RET                                     
RET to 0040E7E0

0040E7E0        ADD ESP
8
0040E7E3        TEST EAX
EAX
0040E7E5        JE SHORT r6002dum.0040E822              
EAX+24 below is where your breakpoint should have brought you from blog post
0040E7E7        MOV EAX
DWORD PTR [EAX+24]             ; DS:[0040015C]=E00000E0Characteristics CODE|INITIALIZED_DATA|UNINITIALIZED_DATA|EXECUTE|READ|WRITE
0040E7EA        SHR EAX
1F
0040E7ED        NOT EAX
0040E7EF        
AND EAX1                              EAX becomes 00000000
0040E7F2        MOV DWORD PTR 
[EBP-4], -2
0040E7F9        MOV ECX
DWORD PTR [EBP-10]
0040E7FC        MOV DWORD PTR FS:[0], ECX
....
....
0040E809        POP EBP
0040E80A        RET                                     
; Return to 004071A8

004071A8        POP ECX                                 

004071A9        TEST EAXEAX                           Test EAX, if 0 we jump on JE to the error msg
004071AB        JE SHORT r6002dum.004071B7              
; If no jump the .section is read onlyno error msg
004071AD        PUSH DWORD PTR 
[EBP+8]                  ; Patch JE to nop or inc eax before test so no jump
004071B0        CALL DWORD PTR 
[41D680]                 ; 
Anyway that is pretty much the posted summed up into one. Hope that explains it easier.
Credits to Ghandi (ARTeam) and KPNC blog post explaining the R6002 error.
Attached Files
File Type: zip mpress.217_r6002.zip (130.1 KB, 26 views)
Reply With Quote
The Following 3 Users Gave Reputation+1 to RedBlkJck For This Useful Post:
axl936 (08-03-2012), giv (08-03-2012), zementmischer (08-03-2012)
  #17  
Old 08-03-2012, 02:43
zementmischer's Avatar
zementmischer zementmischer is offline
Don't mess with concrete
 
Join Date: Mar 2011
Location: Europe
Posts: 216
Rept. Given: 124
Rept. Rcvd 490 Times in 111 Posts
Thanks Given: 12
Thanks Rcvd at 99 Times in 33 Posts
zementmischer Reputation: 400-499 zementmischer Reputation: 400-499 zementmischer Reputation: 400-499 zementmischer Reputation: 400-499 zementmischer Reputation: 400-499
@axl936: And once you have managed to unpack it you should take a look at my 'quick and dirty' patcher/keyfilemaker implementation. I've successfully tested the patcher with both versions (stable and development). The following steps are performed:
  1. Generate a random 1024bit RSA key pair.
  2. Generate a fresh license with this random key and save it as 'license.dat'.
  3. Open the unpacked target and locate the resource which holds the private key blob.
  4. Replace the private key with your own one and save the modifications back to the executable.

The main advantage of this procedure is that it should also work with future versions and different keys (as long as 1024bit RSA keys are used and the blob is stored as "BIN" resource). But you can easily modify the sources by redefining KEYLENGTH and BLOBRSRC - just in case they change the key size or the resource location.

Code:
#include <windows.h>
#include <wincrypt.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>

#define KEYLENGTH (1024 << 16)
#define BLOBRSRC  "BIN"

static LPBYTE lpbyTargetBlob = NULL;

BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCSTR lpszType, LPSTR lpszName, LONG_PTR lParam)
{
    HRSRC hrsrc;
    HGLOBAL hBlob;
    LPBYTE lpbyResource;
    BOOL fRetVal = TRUE;

    hrsrc = FindResourceA(hModule, lpszName, lpszType);
    if (!hrsrc || SizeofResource(hModule, hrsrc) != (DWORD)lParam) return fRetVal;
    if (!(hBlob = LoadResource(hModule, hrsrc))) return fRetVal;
    lpbyResource = (LPBYTE)LockResource(hBlob);
    if (!memcmp(lpbyResource + 8, "RSA2", 4))
    {
        lpbyTargetBlob = (LPBYTE)malloc(lParam);
        memcpy(lpbyTargetBlob, lpbyResource, (DWORD)lParam);
        fRetVal = FALSE;
    }
    UnlockResource(hBlob);
    FreeResource(hBlob);

    return fRetVal;
}

void main(int argc, char* argv[])
{
    LPCSTR szLicense = "zementmischer\0Don't mess with concrete!!!\0forum.exetools.com\0\1\1\1\107";
    CHAR szContainerName[_MAX_PATH] = "";
    HCRYPTPROV hProv;
    HCRYPTKEY hRSAKey;
    LPBYTE lpbyPrivKeyBlob, lpbyLicense, lpbyFileMapping = NULL;
    DWORD cbBlockSize, cbSize, cbPrivKeyBlob = 0, cbContainerName = sizeof(szContainerName), i;
    HANDLE hFile = INVALID_HANDLE_VALUE, hFileMapping = NULL;
    HMODULE hTarget;
    BOOL fSuccess = FALSE;

    if (argc != 2)
    {
        fprintf(stderr, "%s: <unpacked exe>\n", argv[0]);
        return;
    }

    if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0))
    {
        if (GetLastError() != NTE_BAD_KEYSET
        || !CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)
        || !CryptGetProvParam(hProv, PP_CONTAINER, (LPBYTE)szContainerName, &cbContainerName, 0))
        {
            fprintf(stderr, "Failed to open/create key container\n");
            return;
        }
    }

    if (!CryptGenKey(hProv, CALG_RSA_KEYX, KEYLENGTH | CRYPT_EXPORTABLE, &hRSAKey)
    ||  !CryptExportKey(hRSAKey, NULL, PRIVATEKEYBLOB, 0, NULL, &cbPrivKeyBlob))
    {
        fprintf(stderr, "Failed to generate RSA key pair\n");
        goto cleanup;
    }

    lpbyPrivKeyBlob = (LPBYTE)_alloca(cbPrivKeyBlob);
    CryptExportKey(hRSAKey, NULL, PRIVATEKEYBLOB, 0, lpbyPrivKeyBlob, &cbPrivKeyBlob);
    CryptGetKeyParam(hRSAKey, KP_BLOCKLEN, (LPBYTE)&cbBlockSize, &cbSize, 0);
    cbBlockSize = cbBlockSize / 8;
    lpbyLicense = (LPBYTE)_alloca(cbBlockSize);

    hFile = CreateFileA("license.dat", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        fprintf(stderr, "Failed to create license file\n");
        goto cleanup;
    }
    memset(lpbyLicense, 0, cbBlockSize);
    memcpy(lpbyLicense, szLicense, cbBlockSize - 12);
    cbSize = cbBlockSize - 11;
    CryptEncrypt(hRSAKey, NULL, FALSE, 0, lpbyLicense, &cbSize, cbBlockSize);
    WriteFile(hFile, lpbyLicense, cbSize, &cbSize, NULL);
    CloseHandle(hFile);
    hFile = INVALID_HANDLE_VALUE;

    hTarget = LoadLibraryA(argv[1]);
    if (!hTarget)
    {
        fprintf(stderr, "Failed to load target file\n");
        goto cleanup;
    }
    EnumResourceNamesA(hTarget, BLOBRSRC, EnumResNameProc, cbPrivKeyBlob);
    FreeLibrary(hTarget);
    if (!lpbyTargetBlob)
    {
        fprintf(stderr, "Failed to locate RSA blob\n");
        goto cleanup;
    }

    hFile = CreateFileA(argv[1], GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        fprintf(stderr, "Failed to open target file\n");
        goto cleanup;
    }
    cbSize = GetFileSize(hFile, NULL);
    if ((hFileMapping = CreateFileMappingA(hFile, NULL, PAGE_READWRITE, 0, 0, NULL)) != NULL
    &&  (lpbyFileMapping = reinterpret_cast<LPBYTE>(MapViewOfFile(hFileMapping, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, 0))) != NULL)
    {
        for (i = 0; i < cbSize - cbPrivKeyBlob; ++i)
        {
            if (!memcmp(lpbyFileMapping + i, lpbyTargetBlob, cbPrivKeyBlob))
            {
                memcpy(lpbyFileMapping + i, lpbyPrivKeyBlob, cbPrivKeyBlob);
                fSuccess = TRUE;
                break;
            }
        }

        FlushViewOfFile(lpbyFileMapping, 0);
        UnmapViewOfFile(lpbyFileMapping);
    }

cleanup:
    if (hFileMapping) CloseHandle(hFileMapping);
    if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
    if (lpbyTargetBlob) free(lpbyTargetBlob);
    CryptDestroyKey(hRSAKey);
    CryptReleaseContext(hProv, 0);

    if (fSuccess) fprintf(stdout, "File patched\n");
}
__________________
Real programmers don't read manuals.
Reliance on a reference is a hallmark of the novice and the coward.
Reply With Quote
The Following 4 Users Gave Reputation+1 to zementmischer For This Useful Post:
*RemedY* (08-03-2012), axl936 (08-03-2012), giv (08-03-2012), RedBlkJck (08-03-2012)
  #18  
Old 08-03-2012, 04:57
axl936 axl936 is offline
Friend
 
Join Date: Jul 2004
Posts: 46
Rept. Given: 13
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 0
Thanks Rcvd at 0 Times in 0 Posts
axl936 Reputation: 0
Thanks for the wonderful explanation, very complete and accurate!
Now I will try to repeat the steps as indicated from scratch and I want to see if I can do it!

I have effectively chosen a bone too hard for me to start learn unpacking/patching !
Luckily for me you know a lot about this subject, and you've done all the work in a very short time!

A good lesson in rce'ing !!

Thanks..
Reply With Quote
  #19  
Old 08-03-2012, 13:25
giv's Avatar
giv giv is offline
VIP
 
Join Date: Jan 2011
Location: Romania
Posts: 1,657
Rept. Given: 801
Rept. Rcvd 1,283 Times in 561 Posts
Thanks Given: 226
Thanks Rcvd at 562 Times in 240 Posts
giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299 giv Reputation: 1100-1299
Quote:
Originally Posted by axl936 View Post
Thanks for the wonderful explanation, very complete and accurate!
Now I will try to repeat the steps as indicated from scratch and I want to see if I can do it!

I have effectively chosen a bone too hard for me to start learn unpacking/patching !
Luckily for me you know a lot about this subject, and you've done all the work in a very short time!

A good lesson in rce'ing !!

Thanks..
I suggest you to begin with lena151 tutorials which you can find here:
Quote:
http://tuts4you.com/download.php?list.17
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



All times are GMT +8. The time now is 07:42.


Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX, chessgod101
( 1998 - 2024 )