Join the discord

Extracting SWF from Flash Projector

25 Sep, 2011 00:00
Ever wondered how to extract a SWF file from Adobe's Flash Projector? There is already both free and paid (LOL!) programs which should do the trick, but it's so easy that it doesn't worth the effort of downloading or paying (again, LOL!) for them.

Flash projected SWF's are actually a standalone flash player, bundled with the original SWF. The projector contains only the needed flash runtime library, which is... what "bundling" mean.

The structure of a Projector file looks like this:

Standard MZ-PE executable Projector
Original SWF file
DWORD, 0xFA123456Flash Projector "check" value
DWORD, Size of the original SWF file

The executable is designed that way, so it reads his own last 8 bytes, which are the projector check DWORD and the SWF size.
If the "check" DWORD is equal to 0xFA123456, it reads <size of the original SWF> bytes back (excluding the last 8 bytes), and process the data as standard SWF.

So, long story short, here's a small code that will extract SWF file from Projector bundle:
dump_projector.c, poorly written in C#include <stdio.h>
#include <windows.h>

int main() {
    int     szFile;
    char    dataEnd[8];
    DWORD   lpNumberOfBytesRW;
    HANDLE  hfInput,
            hfOutput,
            hMemHeap,
            hHeap;
    
    hfInput = CreateFile("input_projector.exe", GENERIC_READ, 0, NULL,\
                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hfInput == INVALID_HANDLE_VALUE) {
        printf("Cannot open input file for reading!\r\n");
    } else {
        szFile = GetFileSize(hfInput, NULL);
        SetFilePointer(hfInput, szFile-8, NULL, FILE_BEGIN);
        ReadFile(hfInput, dataEnd, 8, &lpNumberOfBytesRW, NULL);
        if (*(DWORD*)&dataEnd == 0xFA123456) { // Check the signature
            hHeap = GetProcessHeap();
            if (hHeap) {
                hMemHeap = (PHANDLE)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, *(DWORD*)&dataEnd[4]);
                SetFilePointer(hfInput, szFile-8-*(DWORD*)&dataEnd[4], NULL, FILE_BEGIN);
                ReadFile(hfInput, hMemHeap, *(DWORD*)&dataEnd[4], &lpNumberOfBytesRW, NULL);
                hfOutput = CreateFile("dumped.swf", GENERIC_WRITE, 0, NULL,\
                                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
                if (hfOutput == INVALID_HANDLE_VALUE) {
                    printf("Cannot create output file for writing!\r\n");
                } else {
                    WriteFile(hfOutput, hMemHeap, *(DWORD*)&dataEnd[4], &lpNumberOfBytesRW, NULL);
                    CloseHandle(hfOutput);
                    printf("Done, check your shiny new dumped.swf! =)\r\n");
                }
                HeapFree(hHeap, 0, hMemHeap);
            } else {
                printf("Can't fetch the process heap!\r\n");
            }
        } else {
            printf("This doesn't seems to be a projector bundle.\r\n");
        }
        CloseHandle(hfInput);
    }
    return 0;
}

Well, that's all. ;)

Comments

* You have an opinion? Let us all hear it!

Guest 22 Jun, 2023 16:54
With only one parameter :

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <string.h>
#include <stddef.h>

#include <string.h>
#include <stdlib.h>
#include <stddef.h>

#if (__STDC_VERSION__ >= 199901L)
#include <stdint.h>
#endif

char *repl_str(const char *str, const char *from, const char *to) {

/* Adjust each of the below values to suit your needs. */

/* Increment positions cache size initially by this number. */
size_t cache_sz_inc = 16;
/* Thereafter, each time capacity needs to be increased,
* multiply the increment by this factor. */
const size_t cache_sz_inc_factor = 3;
/* But never increment capacity by more than this number. */
const size_t cache_sz_inc_max = 1048576;

char *pret, *ret = NULL;
const char *pstr2, *pstr = str;
size_t i, count = 0;
#if (__STDC_VERSION__ >= 199901L)
uintptr_t *pos_cache_tmp, *pos_cache = NULL;
#else
ptrdiff_t *pos_cache_tmp, *pos_cache = NULL;
#endif
size_t cache_sz = 0;
size_t cpylen, orglen, retlen, tolen, fromlen = strlen(from);

/* Find all matches and cache their positions. */
while ((pstr2 = strstr(pstr, from)) != NULL) {
count++;

/* Increase the cache size when necessary. */
if (cache_sz < count) {
cache_sz += cache_sz_inc;
pos_cache_tmp = realloc(pos_cache, sizeof(*pos_cache) * cache_sz);
if (pos_cache_tmp == NULL) {
goto end_repl_str;
} else pos_cache = pos_cache_tmp;
cache_sz_inc *= cache_sz_inc_factor;
if (cache_sz_inc > cache_sz_inc_max) {
cache_sz_inc = cache_sz_inc_max;
}
}

pos_cache[count-1] = pstr2 - str;
pstr = pstr2 + fromlen;
}

orglen = pstr - str + strlen(pstr);

/* Allocate memory for the post-replacement string. */
if (count > 0) {
tolen = strlen(to);
retlen = orglen + (tolen - fromlen) * count;
} else retlen = orglen;
ret = malloc(retlen + 1);
if (ret == NULL) {
goto end_repl_str;
}

if (count == 0) {
/* If no matches, then just duplicate the string. */
strcpy(ret, str);
} else {
/* Otherwise, duplicate the string whilst performing
* the replacements using the position cache. */
pret = ret;
memcpy(pret, str, pos_cache[0]);
pret += pos_cache[0];
for (i = 0; i < count; i++) {
memcpy(pret, to, tolen);
pret += tolen;
pstr = str + pos_cache[i] + fromlen;
cpylen = (i == count-1 ? orglen : pos_cache[i+1]) - pos_cache[i] - fromlen;
memcpy(pret, pstr, cpylen);
pret += cpylen;
}
ret[retlen] = '';
}

end_repl_str:
/* Free the cache and return the post-replacement string,
* which will be NULL in the event of an error. */
free(pos_cache);
return ret;
}


int main(int argc, char *argv[]) {
int szFile;
char dataEnd[8];
uint32_t lpNumberOfBytesRW;
void *hfInput,
*hfOutput,
*hMemHeap,
*hfOutputNameSwf;

if (argc != 2) {
printf("Usage: dump_projector infile outfilern
Example: `dump_projector application.exe`rn");
return 1;
}

hfInput = fopen(argv[1], "rb");
if (hfInput == NULL) {
printf("Cannot open input file for reading!rn");
} else {
fseek(hfInput, -8L, SEEK_END);
szFile = ftell(hfInput);
fread(dataEnd, 8, 1, hfInput);
if (*(uint32_t*)&dataEnd == 0xFA123456) { // Check the signature
hMemHeap = calloc(1, *(uint32_t*)&dataEnd[4]);
if (hMemHeap != NULL) {
fseek(hfInput, szFile-*(uint32_t*)&dataEnd[4], SEEK_SET);
lpNumberOfBytesRW = fread(hMemHeap, 1, *(uint32_t*)&dataEnd[4], hfInput);
hfOutputNameSwf = repl_str(argv[1], ".exe", ".swf");
// hfOutput = fopen(argv[2], "wb");
hfOutput = fopen(hfOutputNameSwf, "wb");
if (hfOutput == NULL) {
printf("Cannot create output file for writing!rn");
} else {
fwrite(hMemHeap, 1, *(uint32_t*)&dataEnd[4], hfOutput);
fclose(hfOutput);
printf("Done! -> %srn", hfOutputNameSwf);
}
free(hMemHeap);
} else {
printf("Can't fetch the process heap!rn");
}
} else {
printf("This doesn't seems to be a projector bundle.rn");
}
fclose(hfInput);
}
return 0;
}
Guest 20 Feb, 2023 01:57
Where do I paste this code exactly, tho?
Guest 07 Oct, 2021 13:46
hi all
Guest 16 Sep, 2021 08:10
Please upload the compiled .exe file!
XpoZed 13 Feb, 2017 03:23
I have no problems with that.
I'm glad you found it useful, and thanks for linking my site. :)
Guest 29 Jan, 2017 07:41
Thanks a lot for the analysis! I have created a POSIX compatible version of the source (i.e. for Linux / Unix) on http://digitalimagecorp.de/software/dump_projector/ for those that need it.
(You didn't specify a license, so please contact me if I should remove the port.)
Guest 20 Jul, 2013 10:36
Thanks man!
© nullsecurity.org 2011-2024 | legal | terms & rules | contacts