Jump to content
Tuts 4 You

Problem With VB6 Exe


StoneHeart

Recommended Posts

Im finishing my exe loader which run exe from memory.


All went fine but now im facing problem with vb6 exe.


When i try loading resource data, the app crash because it cant find the resource.


 


Does anyone know what is the problem with my loader to load vb6 exe?


 


Some example to fix the problem would be nice.


 


Thanks.


 


Link to comment

More details are needed to better understand your issue. How do you launch your executable? And how do you load resources?


Link to comment

@grizzmo


I think all exe can be executed such way. Atleast with relocation table exist.


 


@Nacho_dj


I launch the exe using peloader method ie load it in memory, fix import, fix relocation etc


 


Tested on self code vb6 exe.


I load resource using vb6 load resource method ie loadresstring function.


On normal execution it works but when use peloader, it didnt work.


Got error like resource id 101 doesnt exist.


 


Basically the vb6 exe run when i didnt patch the peb->imagebase but when i patch it, the exe doesnt want to run and an error message appear ie "Error................; quiting"


The error message doesnt come from my code but i think its from vb6 vm.


 


I had no clue with what might produce such error.


 


Please help.


 


P/S The peb patching method that i use was taken from zombie inconexe code (adjustwindowosstructure)


       My peloader were based on that source code.


       Appearently zombie code didnt work with vb6 exe either.


Edited by StoneHeart
Link to comment

Ok, try to find at memory the entire resources section, loaded in the address that they should be, as PE header shows. If they are not loaded at the expected address, the error you mentioned will be displayed for sure.
Resources data are dependent of the RVA address of their PE section, so if they are loaded in a different address, it won't work.

Link to comment

Ok i will try that.


 


...


 


You know, i have tested any exe compiled using delphi and c/c++. All works fine.


Why when i "adjustwindowosstructure" aka patch the peb, the vb6 exe wont run. Without it run.


I think the problem is i really need to patch the peb because if i didnt patch the peb all exe including delphi and c/c++ wont work like resource isnt loading (i know it because when testing gui exe, the icon is missing).


But since when i patch peb the vb6 exe wont run, i cant find the solution for it.


 


Any other idea?


Link to comment

Ok, let's see it in another way.If you dump from memory the executable loaded by the system, and you dump again the executable loaded by your loader, the dumps should be identical, at least in resources section. Try that to find if this condition is reached... any difference found will give you a clue about what is being missed...
 

Link to comment

Im a little bit noob at dumping processes but...

 

Here is a little bit of the patching method ive done before jumping to EP:-

 

dwImageBase = VirtualAlloc(NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
...

PPEB pPeb;
PPEB_LDR_DATA pLdrData;
PLDR_ENTRY pLdrEntry;

__asm PUSH    FS:[0x30]
__asm POP     pPebpPeb->ImageBaseAddress = dwImageBase;
 

Edited by StoneHeart
Link to comment

If you assign an arbitrary address as ImageBase to an executable not owning a relocations data section, it will probably crash.
You must load the executable at Imagebase address of PE header.
So try to force VirtualAlloc to create a region starting at ImageBase address of PE header of your executable.
 

Link to comment

I was on a forum a while ago and downloaded a c++ runpe with loader as you wish, but a few minutes later the runpe thread was closed, because the runpe is worth  5.000 US dollar and wasn't supposed to be there.


 


Could this be possible?


 


Regards,


 


grizzmo


Edited by grizzmo
Link to comment

If you assign an arbitrary address as ImageBase to an executable not owning a relocations data section, it will probably crash.

You must load the executable at Imagebase address of PE header.

So try to force VirtualAlloc to create a region starting at ImageBase address of PE header of your executable.

 

 

The exe has relocation table and all the necassary stuff has been done.

 

I was on a forum a while ago and downloaded a c++ runpe with loader as you wish, but a few minutes later the runpe thread was closed, because the runpe is worth  5.000 US dollar and wasn't supposed to be there.

 

Could this be possible?

 

Regards,

 

grizzmo

 

RunPE need to spawn another exe in suspended state. The one im trying to achieve is like running 2 exe in 1 process (The loader and the exe in memory).

 

---

 

Is there any working sample to run 2 exe in 1 process?

Edited by StoneHeart
Link to comment

But getting the .exe into memory, therefore you should have a runpe, right? Otherwish you can do something like createprocess,  from .exe.


I used to start/load .exe's from an old tutorial from Goppit from ARTeam, which includes explanation and code on loaders to a bit more advanced loaders.


 


Titel of tutorial: Win32_Assembler_Coding_for_Crackers_by_Goppit_v11


 


I can upload a copy of his tutorial, if you want to take a look.


Edited by grizzmo
Link to comment

But getting the .exe into memory, therefore you should have a runpe, right? Otherwish you can do something like createprocess,  from .exe.

I used to start/load .exe's from an old tutorial from Goppit from ARTeam, which includes explanation and code on loaders to a bit more advanced loaders.

 

Titel of tutorial: Win32_Assembler_Coding_for_Crackers_by_Goppit_v11

 

I can upload a copy of his tutorial, if you want to take a look.

 

 

Sure, why not :D

 

---

 

Anyway here is the sample im testing (Source are not mine). It can load vb6 app but cant load resource.


#include <Windows.h>

#define MAKE_ORDINAL(val) (val & 0xffff)

int load_imports(IMAGE_IMPORT_DESCRIPTOR *imp_desc, void *load_address)

{

while (imp_desc->Name || imp_desc->TimeDateStamp) {

IMAGE_THUNK_DATA *name_table, *address_table, *thunk;

char *dll_name = (char *)load_address + imp_desc->Name;

HMODULE module;

module = LoadLibrary(dll_name);

if (!module) {

printf("error loading %s\n", dll_name);

return 0;

}

name_table = (IMAGE_THUNK_DATA *)((char *)load_address + imp_desc->OriginalFirstThunk);

address_table = (IMAGE_THUNK_DATA *)((char *)load_address + imp_desc->FirstThunk);

/* if there is no name table, use address table */

thunk = name_table == load_address ? address_table : name_table;

if (thunk == load_address)

return 0;

while (thunk->u1.AddressOfData) {

unsigned char *func_name;

/* is ordinal? */

if (thunk->u1.Ordinal & IMAGE_ORDINAL_FLAG)

func_name = (unsigned char *)MAKE_ORDINAL(thunk->u1.Ordinal);

else

func_name = ((IMAGE_IMPORT_BY_NAME *)((char *)load_address + thunk->u1.AddressOfData))->Name;

/* address_table->u1.Function = (DWORD)GetProcAddress(module, (char *)func_name); */

address_table->u1.Function = (DWORD)GetProcAddress(module, (char *)func_name);

thunk++;

address_table++;

}

imp_desc++;

}

return 1;

}

void fix_relocations(IMAGE_BASE_RELOCATION *base_reloc, DWORD dir_size,

DWORD new_imgbase, DWORD old_imgbase)

{

IMAGE_BASE_RELOCATION *cur_reloc = base_reloc, *reloc_end;

DWORD delta = new_imgbase - old_imgbase;

reloc_end = (IMAGE_BASE_RELOCATION *)((char *)base_reloc + dir_size);

while (cur_reloc < reloc_end && cur_reloc->VirtualAddress) {

int count = (cur_reloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);

WORD *cur_entry = (WORD *)(cur_reloc + 1);

void *page_va = (void *)((char *)new_imgbase + cur_reloc->VirtualAddress);

while (count--) {

/* is valid x86 relocation? */

if (*cur_entry >> 12 == IMAGE_REL_BASED_HIGHLOW)

*(DWORD *)((char *)page_va + (*cur_entry & 0x0fff)) += delta;

cur_entry++;

}

/* advance to the next one */

cur_reloc = (IMAGE_BASE_RELOCATION *)((char *)cur_reloc + cur_reloc->SizeOfBlock);

}

}

IMAGE_NT_HEADERS *get_nthdrs(void *map)

{

IMAGE_DOS_HEADER *dos_hdr;

dos_hdr = (IMAGE_DOS_HEADER *)map;

return (IMAGE_NT_HEADERS *)((char *)map + dos_hdr->e_lfanew);

}

/* returns EP mem address on success

* NULL on failure

*/

void *load_pe(void *fmap)

{

IMAGE_NT_HEADERS *nthdrs;

IMAGE_DATA_DIRECTORY *reloc_entry, *imp_entry;

void *vmap;

WORD nsections, i;

IMAGE_SECTION_HEADER *sec_hdr;

size_t hdrs_size;

IMAGE_BASE_RELOCATION *base_reloc;

nthdrs = get_nthdrs(fmap);

reloc_entry = &nthdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];

/* no reloc info? */

if (!reloc_entry->VirtualAddress)

return NULL;

/* allocate executable mem (.SizeOfImage) */

vmap = VirtualAlloc(NULL, nthdrs->OptionalHeader.SizeOfImage,

MEM_COMMIT, PAGE_EXECUTE_READWRITE);

if (!vmap)

return NULL;

/* copy the Image + Sec hdrs */

nsections = nthdrs->FileHeader.NumberOfSections;

sec_hdr = IMAGE_FIRST_SECTION(nthdrs);

hdrs_size = (char *)(sec_hdr + nsections) - (char *)fmap;

memcpy(vmap, fmap, hdrs_size);

/* copy the sections */

for (i = 0; i < nsections; i++) {

size_t sec_size;

sec_size = sec_hdr.SizeOfRawData;

memcpy((char *)vmap + sec_hdr.VirtualAddress,

(char *)fmap + sec_hdr.PointerToRawData, sec_size);

}

/* load dlls */

imp_entry = &nthdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];

if (!load_imports((IMAGE_IMPORT_DESCRIPTOR *)

((char *)vmap + imp_entry->VirtualAddress), vmap))

goto cleanup;

/* fix relocations */

base_reloc = (IMAGE_BASE_RELOCATION *)((char *)vmap + reloc_entry->VirtualAddress);

fix_relocations(base_reloc, reloc_entry->Size,

(DWORD)vmap, nthdrs->OptionalHeader.ImageBase);

return (void *)((char *)vmap + nthdrs->OptionalHeader.AddressOfEntryPoint);

cleanup:

VirtualFree(vmap, 0, MEM_RELEASE);

return NULL;

}

int vmem_exec(void *fmap)

{

void *ep;

ep = load_pe(fmap);

if (!ep)

return 0;

__asm {

mov ebx, fs:[0x30]

mov eax, ep

call eax

}

return 1;

}

BYTE *FileToMem(LPCSTR szFileName, DWORD *dwSize)

{

BOOL bResult = FALSE;

HANDLE hFile;

DWORD dwRead;

BYTE *pBuffer = NULL;

hFile = CreateFileA(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);

if (hFile)

{

*dwSize = GetFileSize(hFile, NULL);

if (*dwSize > 0)

{

pBuffer = (BYTE *)VirtualAlloc(NULL, *dwSize + 3, MEM_COMMIT, PAGE_READWRITE);

if (pBuffer)

{

SetFilePointer(hFile, NULL, NULL, FILE_BEGIN);

ReadFile(hFile, pBuffer, *dwSize, &dwRead, NULL);

if (dwRead == *dwSize)

return pBuffer;

}

}

CloseHandle(hFile);

}

return NULL;

}

int _tmain(int argc, _TCHAR* argv[])

{

BYTE *bvByte;

DWORD dwSize;

bvByte = FileToMem("c:\\vbapp.exe", &dwSize);

vmem_exec(bvByte);

return 0;

}

Any way around to make it to work with vb app so that the resource is working?

 

Thanks.

Link to comment

ASM tutorial from Goppit ARTeam:


 


A bit late, but this afternoon mediafire kept uploading and uploading over and over. I left their webpage, because off the error.


 


I now looked and the tutorial was uploaded multiple times!


 


Link removed.

Edited by grizzmo
Link to comment

What do you mean with: Can't load resource? You mean files needed by vb6.exe?


 


I send you a pm, maybe wiht an answer.

Link to comment

What do you mean with: Can't load resource? You mean files needed by vb6.exe?

 

I send you a pm, maybe wiht an answer.

 

Can't load the vb6 app resource like string data, image etc.

 

Thanks for the pm but still not solving the issues.

 

Anyone who try the source do help find the fix.

 

Thanks.

Edited by StoneHeart
Link to comment

As I told you, dump it to find if resources are at the right address, and addresses in the executable referencing resources are right also.


 


To dump it: get CFF ExploreSuite, open Task manager, select your process and choose from contextual menu: "Dump PE"


 


Then compare with dump of the executable loaded by system itself...


Link to comment

Correct me, if I am wrong:


 


You want to go programming in visual basic or start visual basic with the main exe = vb6.exe, loaded in memory instead of clicking on the file in your vb6 folder or the shortcut?


 


Is this pure for the fact you can't get it to run yet, while other files do run, or do you want the file to run in memory for a purpose?


 


To be more clear: with resources you mean resources of the vb6.exe or do you mean all the files vb6.exe is accessing when you are programming?


 


Edit: I found this code, I am looking now too  :prop:


 


I hope this helps.



lude <stdio.h>
#include <windows.h>
#include <cstdlib>
#include <string>
using namespace std; // [SRC] Patch ImageBase in PEB
// http://www.ic0de.org/showthread.php?8435-SRC-Patch-ImageBase-in-PEB
//
// Coded by RTFLOL
// Released on http://hackhound.org/
// Date: 2/1/2010 /*
    This application patches an ImageBase of an external executable and replaces it
    with the path of this file.
    Please give credits if you use. Don't be a ripper fag, k? 
*/ typedef struct _UNICODE_STRING
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING; typedef struct _PROCESS_BASIC_INFORMATION
{
    LONG ExitStatus;
    PVOID PebBaseAddress;
    ULONG_PTR AffinityMask;
    LONG BasePriority;
    ULONG_PTR UniqueProcessId;
    ULONG_PTR ParentProcessId;
} PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; typedef LONG (WINAPI *_NtQueryInformationProcess)(
    HANDLE ProcessHandle,
    DWORD ProcessInformationClass,
    PVOID ProcessInformation,
    DWORD ProcessInformationLength,
    PDWORD ReturnLength
); _NtQueryInformationProcess NtQueryInformationProcess =
        (_NtQueryInformationProcess)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationProcess"); int Patch(DWORD dwPid, WCHAR *path, WCHAR *cmdLine)
{
    //
    // Get Handle
    //     HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);     PROCESS_BASIC_INFORMATION pbi;
    NtQueryInformationProcess(hProcess, 0, &pbi, sizeof(pbi), NULL);
    PVOID peb = pbi.PebBaseAddress;     PVOID rtlUserProcParamsAddress = NULL;
    if (!ReadProcessMemory(hProcess, (PCHAR)peb + 0x10, &rtlUserProcParamsAddress, sizeof(PVOID), NULL))
    {
        printf("ERROR: Could not read rtlUserProcParamsAddress!\n");
        return GetLastError();
    }     UNICODE_STRING Current_ImageBase;
    if (!ReadProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 0x38, &Current_ImageBase, sizeof(Current_ImageBase), NULL))
    {
        printf("ERROR: Could not read ImageBase of the target process.\n");
        return GetLastError(); 
    }     //
    // Update data
    //     WCHAR *input;
    LPVOID pNewAddr;     //
    // <-- Path -->
    //     input = path;     Current_ImageBase.Length = lstrlenW(input) * 2;
    pNewAddr = VirtualAllocEx(hProcess, NULL, Current_ImageBase.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (!pNewAddr)
    {
        printf("ERROR: Could not allocate memory in target process.\n");
        return GetLastError();
    }
    if(!WriteProcessMemory(hProcess, pNewAddr, input, Current_ImageBase.Length, NULL))
    {
        printf("ERROR: Failed to write to address.\n");
        return GetLastError();
    }     Current_ImageBase.Buffer = (WCHAR*)pNewAddr;
    if(!WriteProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 0x38, &Current_ImageBase, sizeof(Current_ImageBase), NULL))
    {
        printf("ERROR: Failed to reflect change back to PEB.\n");
        return GetLastError();
    }     //
    // <-- cmdLine -->
    //     input = cmdLine;     Current_ImageBase.Length = lstrlenW(input) * 2;
    pNewAddr = VirtualAllocEx(hProcess, NULL, Current_ImageBase.Length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (!pNewAddr)
    {
        printf("ERROR: Could not allocate memory in target process.\n");
        return GetLastError();
    }
    if(!WriteProcessMemory(hProcess, pNewAddr, input, Current_ImageBase.Length, NULL))
    {
        printf("ERROR: Failed to write to address.\n");
        return GetLastError();
    }     Current_ImageBase.Buffer = (WCHAR*)pNewAddr;
    if(!WriteProcessMemory(hProcess, (PCHAR)rtlUserProcParamsAddress + 0x40, &Current_ImageBase, sizeof(Current_ImageBase), NULL))
    {
        printf("ERROR: Failed to reflect change back to PEB.\n");
        return GetLastError();
    }     //
    // Done
    //     return 1;
} int main(void)
{
    wchar_t
        *path = L"c:\\windows\\aaa.cmd",
        *cmdLine = L"c:\\windows\\aaa.cmd test";     if (Patch(
        3032,
        path,
        cmdLine))
    {
        printf("\n... All done. <!>\n");
    }
    else
    {
        printf("\n... Faile'd. <!>.\n");
    }     system("PAUSE");
    return 0;
}

Edited by grizzmo
Link to comment

As I told you, dump it to find if resources are at the right address, and addresses in the executable referencing resources are right also.

 

To dump it: get CFF ExploreSuite, open Task manager, select your process and choose from contextual menu: "Dump PE"

 

Then compare with dump of the executable loaded by system itself...

 

Here is the file for testing with the source ive posted above.

If you run the file normally, all works fine but when loaded using the loader something went wrong with the resource.

Hope you can help find the solution.

 

TestForLoader.rar

 

Here is the vb code for the test app.

Option ExplicitPrivate Declare Function GetModuleFileName Lib "kernel32" Alias "GetModuleFileNameA" (ByVal hModule As Long, ByVal lpFileName As String, ByVal nSize As Long) As LongPrivate Sub Command1_Click()    Dim s As String * 260        On Error GoTo Hell        GetModuleFileName 0, s, 260        MsgBox s, , "Exe Path"        Exit Sub    Hell:    MsgBox Err.Description, , "Error!"End SubPrivate Sub Command2_Click()    Dim s As String        On Error GoTo Hell        s = LoadResString(101) 'Should return Hello World!        MsgBox s, , "It works!"         Exit Sub    Hell:    MsgBox Err.Description, , "Error!"End SubPrivate Sub Command3_Click()    EndEnd Sub

Correct me, if I am wrong:

You want to go programming in visual basic or start visual basic with the main exe = vb6.exe, loaded in memory instead of clicking on the file in your vb6 folder or the shortcut?

Is this pure for the fact you can't get it to run yet, while other files do run, or do you want the file to run in memory for a purpose?

To be more clear: with resources you mean resources of the vb6.exe or do you mean all the files vb6.exe is accessing when you are programming?

I made a vb6 app, store it inside loader as a resource data. I extract the exe bin to memory then execute it.

Its much like runpe you told me but this method im using is somewhat different.

It can run 2 exe in 1 process. Not using process howling/forking etc.

Btw, thanks for the source but i already test it (same issues =\) before i post my problem here :D

Edited by StoneHeart
Link to comment

I just looked here again.


 


"I made a vb6 app, store it inside loader as a resource data. I extract the exe bin to memory then execute it."


 


Here is something which make me doubt:


 


" I extract the exe bin to memory then execute it."


 


I can do these things with vb.net and this is not how it works.


 


grizzmo

Link to comment

I just looked here again.

 

"I made a vb6 app, store it inside loader as a resource data. I extract the exe bin to memory then execute it."

 

Here is something which make me doubt:

 

" I extract the exe bin to memory then execute it.

 

I can do these things with vb.net and this is not how it works.

 

grizzmo

 

I can do it too with c++ for .net app but its only working for .net based app though its a different story on what i wanna achieve here.

 

My stuff works fine with other app but i dunno how to solve the issues with vb6 app =\

 

Since i have posted the source and sample app to test with, does anyone found any clue on what makes the issues?

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...