Reversing CodeFusion Wizard Patch Files

24 minute read

CodeFusion Wizard was an advanced patch generation tool created by Krichmar Kobi. It was originally designed for Windows 9x/NT in the 1990s. The last version that was released to the public was v3 before the official site was taken offline. While the tool itself is outdated and ‘dead’ at this point, there are still a lot of old patches, trainers and modifications for various games that make use of this tool. With CodeFusion Wizard, users can easily create patches for any kind of file that can do various things such as:

  • Compare two files and generate a patch file to apply the differences.
  • Add data to the given target file.
  • Edit data in the given target file.
  • Use ‘Find and Replace’ style scanning to apply patches.
  • Truncate the file at a given offset.

You can find a snapshot of the CodeFusion Wizard website here:

CodeFusion

How do CodeFusion patch files work?

When a user runs the CodeFusion Wizard tool, they are prompted to input several bits of information about their patch file. Things such as a title, caption, comments/info about what the patch will do, basic about information, etc. Then the user can select multiple target files that should be patched by their patcher file. When a target file is selected, the user can then input several types of patches that they’d wish to apply to the target, or they can do a file comparison to another target file to apply the differences between the two files.

After the user has entered all the information about their desired patch, they can then save and generate a new patcher executable with the given information. CodeFusion will then create a pre-generated executable (depending on the settings selected, the executable used will vary) that is used as a base/skeleton patch executable. This executable, by itself, is just a generic tool that holds all the functionality to apply the various patches that are offered by CodeFusion. However, by itself, the executable is useless because it requires the additional data that is added when building the patcher.

During the build process, CodeFusion will serialize the information the user has given in the Wizard into a block of data. Depending on the settings used, some of this information can be ‘encrypted’ when this step happens. Once the block of data is serialized, it is then injected to the end of the generic patch executable as an overlay. The build process will also inject any desired icons that the user has selected to be used with the patcher to overwrite the default CodeFusion icon.

The build process has some extra steps that can take place based on the users desired selected options:

  • If Encrypt Executable Data is selected, then all strings and patch information data will be XOR encoded.
  • If Pack Executable File > Internal is selected, then a UPX packed generic patcher executable will be used instead of the raw patcher.
  • If Pack Executable File > External PE-Packer is selected, then when the user attempts to build the resulting patcher, the build process will first request the user apply their desired packer to the generic patcher executable. If successful, it will then apply the other information to this custom packed/protected file instead.

Initial Analysis: CodeFusion.exe

To start with the reversing process, we need to first take a look at the main tool executable as it is what generates everything. The first thing I generally do with any executable is look at it in several PE related tools. A couple that I would suggest are:

CFF Explorer Detect It Easy ExeInfoPe

From here, we can see that the main tool executable is packed using UPX. However, it is an old version of UPX so it is not possible to use the latest / newest versions of UPX.exe to unpack the file with the -d flag. Instead, you will either need to manually unpack the file or find an old copy of UPX that supports this old of a version. I won’t go into detail about how to unpack UPX as it is fairly easy, straight forward and heavily documented across the web.

Once the file is unpacked, we can take a second look to get an idea of what we are dealing with and what all this file contains.

Loading into CFF Explorer again shows the file is likely a Borland Delphi executable. Looking at the files resources, we can find the bundled generic patcher executables as well.

CFF Explorer 2

Here, the SFXDATA resources are the generic patchers.

  • SFXFULL is the raw unpacked generic patcher.
  • SFXPACK is the packed generic patcher. (Packed with UPX.)

We can use CFF Explorer to save these resources for later. Mainly, we just need/want the SFXFULL file as its already unpacked. Once extracted you’ll notice that if you try to run the SFXFULL executable, nothing will happen. This is normal as it has no built overlay information appended to it telling it how to function. When no overlay is detected, the program just closes.

Choosing A Target

At this point, we have a choice on how we want to approach the next steps of reversing the overlay information. This is due to the nature of how CodeFusion works.

  1. CodeFusion.exe - The main executable is used to generate the patchers, because of this we can target this route to reverse the build process and see how the overlay is built along with how the patcher executable is generated in full. The advantage to using this file to do the reversing is that we have access to the full build process functionality. However, we also have a larger target in comparison to the generic patcher executable, which means there is a lot of extra function bloat we would have to work through.

  2. SFXFULL.exe - The patcher executables function by reading the overlay, therefore we know that the information needed to decrypt and read the overlay data is all included here. The advantage to using this file to do the reversing is that we have a much smaller target with a more focused set of functionality. However, we only have access to the end-result information and how its read. In this case, this is more than enough to work with though.

For the sake of this post, I’ll be starting with the CodeFusion.exe that I unpacked as the focus here. Being that this file is Borland, the symbol information was left in so we can see several of the function names, including the various form callbacks, button click functions, etc. This helps us directly find the functions we need.

Finding The Build Function

The next steps will involve reversing several functions to understand how CodeFusion works. I would recommend making use of one of the many disassemblers available, ideally one with a decompiler as well. I personally prefer IDA, however you can also use Ghidra if you cannot afford IDA.

Once we open up the unpacked CodeFusion executable, we can quickly see several of the form and button function names are still present. With that information, we can easily track down the function used when building a patcher, which is: TMainForm_btMakeEXEClick

This function starts by applying an exception filter and then begins checking the status of the users various input to generate a patcher. Going into the first call of this function after the exception code, we can find a call to SendMessage using the message id 0x1004. This id is equal to the macro: LVM_GETITEMCOUNT which is used to get a list views item count. So we can rename the function as FUNC_GetListViewCnt

Skimming through the start of this function we can see some basics of checking that the uesr has setup a proper patcher which requires at least 1 file entry. This looks like the following:

int __usercall TMainForm_btMakeEXEClick@<eax>(int *a1@<eax>, int a2@<ebx>, int a3@<esi>)
{
    // Removed local variables..

    v30 = 0;
    v29 = 0;
    v28 = a2;
    v27 = a3;
    v31 = a1;
    v26 = &savedregs;
    v25[1] = &loc_49044F;
    v25[0] = NtCurrentTeb()->NtTib.ExceptionList;
    __writefsdword(0, v25);

    if ( !FUNC_GetLVCnt(*(a1[166] + 304)) )                 // Check file entry count..
    {
        LOBYTE(v3) = 1;
        sub_43FAD0(&str_err_nofiles[1], v3, word_49045C, 0);// No files in project error message..
        goto LABEL_24;
    }

    cnt = FUNC_GetLVCnt(*(v31[166] + 304));                 // Get the file entry count..

    // Removed extra code..
}

We can also debug the CodeFusion executable while we step through these functions to see what the various blocks of data equate to. For example, we can determine that a function that comes up next is checking if the user has selected to encrypt the patcher information.

bool __fastcall FUNC_CheckEncryptExecutableData(int a1)
{
    return *(a1 + 286) == 1;
}

Following more into the TMainForm_btMakeEXEClick function, we can find that the actual build function as it makes use of the overlay signature:

  • @._P-DATA_.@

Which is used inside of: sub_48EDB0 Using either IDA or Ghidra’s means of finding cross references (xref), wecan see this function is called in several locations.

ida xrefs

We can see that there are two main functions that this is being called from:

  • TMainForm_btMakeEXEClick - The main build button callback. The multiple calls here make use of different arguments which state the build step being applied.
  • TMainForm_miSaveClick - The main window menu bar ‘Save’ icon button callback. This calls the same function with a set parameter marking the save attempt to be a project file and not an actual patch executable.

When the user saves a project using the TMainForm_miSaveClick function, then the build process is invoked using a flag stating to skip the patch generation steps, but to build the overlay in a different manner. This step creates the .cfp project files users can continue to reopen and edit at a later date. When this happens, the same overlay building happens but extra steps are taken to serialize additional data such as comments that are not saved to the actual patchers.

Now that we know what the build function is, we can focus on it more specifically. I will be renaming the function to FUNC_BuildFunc going forward as well. The parameters of this function can be determined through reversing and debugging the process trying to build fake patchers and seeing how things work. The parameters of the function look like this:

int __fastcall FUNC_BuildFunc(int *proj, const char *path, char is_save_proj, char a4, char a5)
  • proj - The project object which holds the various pointers to the user entered project information.
  • path - The path to the file that will be saved/generated.
  • is_save_proj - Flag that states if the build call should save a project (.cfp) or if an patcher executable is being made.
  • a4 - Flag used with the encrypted/packed status options.
  • a5 - Flag used with the encrypted/packed status options.

a4 and a5 are not that important to label specifically, we can determine the steps of the function through further reversing.

Reversing / Debugging The Build Function

Given that we’ve found the build function now, we can easily reverse and debug the function as needed. It is also pretty easy to take a guess at what some functions do based on the pointers that are used with the function calls. Since the CodeFusion executable is made with Delphi, a lot of information is still left in the binary such as object type names and such.

The start of the build function creates several streams which are used to write the different parts of the information that will be stored. Those calls look like this:

    FUNC_AddRef(path);
    sub_403FE4(&version, off_45F9E0);

    v5 = off_493870;
    v25 = &savedregs;
    v24 = &loc_48F675;
    exceptionlist = NtCurrentTeb()->NtTib.ExceptionList;
    __writefsdword(0, &exceptionlist);

    mstream1 = FUNC_CreateMemStream(off_40CC14, 1);         // create memory stream..
    mstream2 = FUNC_CreateMemStream(off_40CC14, 1);         // create memory stream..
    mstream3 = FUNC_CreateTIcon(off_4157E4, 1);             // create TIcon memory stream instance..

Next we can tell that the next step is skipped if just the project itself is being saved:

    if ( is_save_proj_ )
        goto LABEL_12;

The next steps prepare how the generic patcher executable will be determined and extracted. This block of code determines which of the two packer executables are used (SFXPACK or SFXFULL). Once the proper string is obtained based on the users configurations, then the resource is loaded from CodeFusion.exe’s resources and moved into the mstream1 object:

    if ( a4 || a5 )
    {
        if ( FUNC_CheckEncryptExecutableData(proj_[172]) && a4 )
        {
            v34 = 2874;
            FUNC_GetString(&v36, &str_SFXPACK[1]); // Get string: SFXPACK
        }
        else
        {
            v34 = 27646;
            FUNC_GetString(&v36, &str_SFXFULL[1]); // Get string: SFXFULL
        }

        mstream4 = FUNC_CreateMemStream(off_40CC14, 1);     // create memory stream..
        FUNC_CopyResource(&v36, &str_SFXDATA[1], &mstream4);
        sub_4102BC(mstream4, mstream1);
        FUNC_ReleaseStream(mstream4);
    }
    else
    {
        sub_4103A8(mstream1);
        v6 = sub_40FE48(mstream1);
        (*(*mstream1 + 12))(mstream1, v6, 0, v22, v21, v20);
    }

The next step the builder function does is builds the overlay information. This part of the function is shared with the project building as well, and makes use of several additional writes/handling based on if a project file is being saved or not. We will not be covering the handling of how the project saving works. We are solely looking at the way patcher files work.

We can see the first call that happens here is:

if ( a4 || !a5 )
    {

LABEL_12:
        (*(*mstream1 + 8))(mstream1, &str____P_DATA___[1], 12);// write signature

We can determine what this function actually does by debugging the CodeFusion executable and breaking on this location. (0x48EF0A)

0048EF05     | 8B45 D4          | mov eax,dword ptr ss:[ebp-2C]    |
0048EF08     | 8B18             | mov ebx,dword ptr ds:[eax]       |
0048EF0A     | FF53 08          | call dword ptr ds:[ebx+8]        | <== Call Here
0048EF0D     | 807D CB 00       | cmp byte ptr ss:[ebp-35],0       |
0048EF11     | 74 50            | je codefusion__unpacked.48EF63   |
0048EF13     | 8B45 D0          | mov eax,dword ptr ss:[ebp-30]    |
0048EF16     | 8B80 70020000    | mov eax,dword ptr ds:[eax+270]   |
0048EF1C     | 8B80 B8000000    | mov eax,dword ptr ds:[eax+B8]    |

We can step into this call dword ptr ds:[ebx+8] and find the address that is actually called, which is: 0x410510

Looking into this function, it is pretty clear that it is a means of memory copying (ie. memcpy) which is attached to a memory stream. This means it’s likely a read or write function. Debugging more we can determine that this is a write function as the copies being made are to the stream itself from a given bit of data. In this case, this is a function that works in a manner such as:

stream->Write('@._P-DATA_.@', 12);

This will write the overlay signature to the stream and advance the current stream position forward 12 bytes.

Following the same reversing, we can move onto the next part of the overlay that is written, the version and encrypted flag:

        version = *off_4937A4[0];                           // 4
        (*(*mstream1 + 8))(mstream1, &version, 1);          // write version

        if ( is_save_proj_ )
            is_encrypted[0] = *off_49370C;
        else
            is_encrypted[0] = FUNC_CheckEncryptExecutableData(proj_[171]);

        (*(*mstream1 + 8))(mstream1, is_encrypted, 1);      // write is_encrypted flag

Next, we have the first block of unknown information being written through a set of multiple calls.

0048EFB0     | 8D95 A0FCFFFF    | lea edx,dword ptr ss:[ebp-360]       |
0048EFB6     | 8B45 D0          | mov eax,dword ptr ss:[ebp-30]        |
0048EFB9     | 8B80 5C020000    | mov eax,dword ptr ds:[eax+25C]       |
0048EFBF     | E8 9C10F9FF      | call codefusion__unpacked.420060     | <== Obtains a string and returns its size..
0048EFC4     | 8B95 A0FCFFFF    | mov edx,dword ptr ss:[ebp-360]       |
0048EFCA     | 8D45 DC          | lea eax,dword ptr ss:[ebp-24]        |
0048EFCD     | E8 BE49F7FF      | call codefusion__unpacked.403990     |
0048EFD2     | 55               | push ebp                             |
0048EFD3     | 8D85 A0FBFFFF    | lea eax,dword ptr ss:[ebp-460]       |
0048EFD9     | 8B55 DC          | mov edx,dword ptr ss:[ebp-24]        |
0048EFDC     | B9 FF000000      | mov ecx,FF                           |
0048EFE1     | E8 6A4BF7FF      | call codefusion__unpacked.403B50     | <== Serializes the string and its length together.. (size|string)
0048EFE6     | 8D85 A0FBFFFF    | lea eax,dword ptr ss:[ebp-460]       |
0048EFEC     | E8 FFFCFFFF      | call codefusion__unpacked.48ECF0     | <== Writes the string
0048EFF1     | 59               | pop ecx                              |

The function that writes the string (which I’ve named FUNC_WriteData) is responsible for writing data to the stream. This also handles encrypting the data that is given to it if the user has selected to encrypt the overlay information. The encryption handling looks like the following: (0x45543C) (Some parts of the function have been removed to save space.)

_DWORD *__fastcall FUNC_EncryptData(char *input, volatile __int32 *output)
{
    FUNC_AddRef(input);

    len = FUNC_GetStringLen(input);
    if ( len > 0 )
    {
        v4 = 1;
        do
        {
            v5 = sub_403D44(&input);
            v5[v4 - 1] = v4 ^ input[v4 - 1];
            ++v4;
            --len;
        }
        while ( len );
    }

    sub_403990(output, input);
    return FUNC_Release(&input);
}

When a string or block of data is written to the stream, it is written in a serialized manner where it is prefixed with its own size as a byte. For example, if the string ‘Hello world.’ is being written to the stream, then it would be written as:

0C 48 65 6C 6C 6F 20 77 6F 72 6C 64 2E

Given that the encryption is a simple rolling XOR, the size of the encrypted and unencrypted data is the same, so the encryption can be applied on the fly and does not cause the size to change.

With this section understood now, we can debug and see what each thing is being written now when building a patcher:

        sub_420060(proj_[151], &txt_size);
        sub_403990(&caption_text, txt_size);
        FUNC_MakeData(txt_data, caption_text, 255);
        FUNC_WriteData(txt_data, &savedregs);               // write caption string

        sub_420060(proj_[157], &txt_size);
        sub_403990(&title_txt, txt_size);
        FUNC_MakeData(txt_data, title_txt, 255);
        FUNC_WriteData(txt_data, &savedregs);               // write title string

        (*(**(proj_[152] + 304) + 28))(*(proj_[152] + 304), &v27); // calls 0x436A04 which calls sub_420060 to obtain the comment string..
        sub_403990(&comment_txt, v27);
        FUNC_MakeData(txt_data, comment_txt, 255);
        FUNC_WriteData(txt_data, &savedregs);               // write comment string

        sub_420060(*(*off_4937F4 + 524), &txt_size);
        sub_403990(&about_txt, txt_size);
        FUNC_MakeData(txt_data, about_txt, 255);
        FUNC_WriteData(txt_data, &savedregs);               // write about string

        sub_420060(*(*off_4937F4 + 488), &txt_size);
        sub_403990(&button1_txt, txt_size);
        FUNC_MakeData(txt_data, button1_txt, 255);
        FUNC_WriteData(txt_data, &savedregs);               // write button1 txt string

        sub_420060(*(*off_4937F4 + 480), &txt_size);
        sub_403990(&button1_url, txt_size);
        FUNC_MakeData(txt_data, button1_url, 255);
        FUNC_WriteData(txt_data, &savedregs);               // write button1 url string

        sub_420060(*(*off_4937F4 + 512), &txt_size);
        sub_403990(&button2_txt, txt_size);
        FUNC_MakeData(txt_data, button2_txt, 255);
        FUNC_WriteData(txt_data, &savedregs);               // write button2 txt string

        sub_420060(*(*off_4937F4 + 508), &txt_size);
        sub_403990(&button2_url, txt_size);
        FUNC_MakeData(txt_data, button2_url, 255);
        FUNC_WriteData(txt_data, &savedregs);               // write button2 url string

The next call that happens is another one where we can look into and see a SendMessage call again, however if we are renaming things we should see this is a wrapper around getting a list view item count. (I have named this call FUNC_GetLVCnt) This call is being used here to obtain the file entry count and write that to the stream:

        file_cnt[0] = FUNC_GetLVCnt(*(proj_[166] + 304));   // get file count
        (*(*mstream1 + 8))(mstream1, file_cnt, 1);          // Write file count

Continuing forward, while debugging we can determine what the next steps of the build process is doing, which is getting the file entry count and looping over each entry within that list view:

        if ( file_cnt[0] )
        {
            v8 = FUNC_GetLVCnt(*(proj_[166] + 304)) - 1;
            if ( v8 >= 0 )
            {
                v33 = v8 + 1;
                v40 = 0;
                do
                {
                    v9 = sub_44AB58(*(proj_[166] + 304), v40);  // get list view item lParam obj
                    *v5 = (*(**(v9 + 8) + 24))(*(v9 + 8), 0);   // get list item

The function 0x44AB58 used here is a wrapper around another SendMessage call used to get a list view item via LVM_GETITEMA. This function will obtain the list view item as its LVITEM structure type and return its lParam value, which holds a pointer to a custom file entry object type. This object is used to get the various properties of the given file entry list view item.

Next, we can continue debugging and watch the calls being made to FUNC_MakeData and FUNC_WriteData to see which pieces of data are being written to the overlay memory stream:

                    FUNC_MakeData(txt_data, *(*v5 + 4), 255);
                    FUNC_WriteData(txt_data, &savedregs);               // write file name

                    (*(*mstream1 + 8))(mstream1, *v5 + 8, 4);           // write file size

                    FUNC_MakeData(txt_data, *(*v5 + 12), 255);
                    FUNC_WriteData(txt_data, &savedregs);               // write file size string

                    FUNC_MakeData(txt_data, *(*v5 + 16), 255);
                    FUNC_WriteData(txt_data, &savedregs);               // write date string

                    FUNC_MakeData(txt_data, *(*v5 + 20), 255);
                    FUNC_WriteData(txt_data, &savedregs);               // write filter string (open file dialog filter)

                    (*(*mstream1 + 8))(mstream1, *v5 + 0x18, 4);        // write checksum (crc32)
                    (*(*mstream1 + 8))(mstream1, *v5 + 0x1C, 1);        // write check file size flag
                    (*(*mstream1 + 8))(mstream1, *v5 + 0x1D, 1);        // write check file checksum flag
                    (*(*mstream1 + 8))(mstream1, *v5 + 0x1E, 1);        // write show file date flag
                    (*(*mstream1 + 8))(mstream1, *v5 + 0x1F, 1);        // write unknown00

                    FUNC_MakeData(txt_data, *(*v5 + 32), 255);
                    FUNC_WriteData(txt_data, &savedregs);               // write unknown01

                    *(*v5 + 36) = (*(**(*v5 + 40) + 20))(*(*v5 + 40));  // get file entry patch count
                    (*(*mstream1 + 8))(mstream1, *v5 + 36, 4);          // write patch count

This step is done in a loop writing each file entry to the overlay stream. However, before stepping to the next file entry, the current file entries patch information is written. This keeps each file and its patches together in the overlay instead of being broken into separate tables or similar. The methods used to write the patch information are the same as the previous data handling, so we can continue to debug and follow / see which data is being written:

                    if ( *(*v5 + 36) && *(*v5 + 36) - 1 >= 0 )
                    {
                        v32 = *(*v5 + 36);
                        v11 = 0;
                        do
                        {
                            v12 = (*(**(*v5 + 40) + 24))(*(*v5 + 40), v11);
                            (*(*mstream1 + 8))(mstream1, v12 + 4, 1);   // write patch type

                            v13 = (*(**(*v5 + 40) + 24))(*(*v5 + 40), v11);
                            (*(*mstream1 + 8))(mstream1, v13 + 8, 4);   // write patch offset

                            v14 = (*(**(*v5 + 40) + 24))(*(*v5 + 40), v11);
                            sub_45576C(*(v14 + 12), &v27);
                            FUNC_MakeData(txt_data, v27, 255);
                            FUNC_WriteData(txt_data, &savedregs);       // write patch data1

                            if ( is_save_proj_ || *((*(**(*v5 + 40) + 24))(*(*v5 + 40), v11) + 4) )
                            {
                                v15 = (*(**(*v5 + 40) + 24))(*(*v5 + 40), v11);
                                sub_45576C(*(v15 + 16), &v27);
                                FUNC_MakeData(txt_data, v27, 255);
                                FUNC_WriteData(txt_data, &savedregs);   // write patch data2
                            }

                            ++v11;
                            --v32;
                        }
                        while ( v32 );
                    }

The last step left is writing the selected file icon, if one was choosen to overwrite the default icon. After that, the stream is written to the given path:

    if ( !is_save_proj_ && (a4 || a5) )
    {
        sub_410358(mstream2);
        v18 = sub_4194E0(*(proj_[156] + 184));
        (*(*v18 + 84))(v18, mstream2);
        (*(*mstream2 + 12))(mstream2, 0, 0);
        (*(*mstream2 + 4))(mstream2, v30, 766);
        sub_40FE3C(mstream1, v34 + 22);
        (*(*mstream1 + 8))(mstream1, v31, 744);             // write the icon data..
    }

    FUNC_WriteStream(mstream1, path_);                      // Write the final patch stream..

    // Cleanup of objects/streams removed to save space..

At this point the patcher is written to disk and is ready for use!

A More Focused Look

The above is a bit of a long read, so in this section we’ll just cover exactly what is written in the overlay in a pseudo code manner. The following block of code is designed to mimic the above code but with the bloat removed and to keep things a bit more specific.

// 'write' is assumed to be: write(value, size)..
// 'write_data' is assumed to be: write_data(value, size) which writes the size (byte) then the data/string..

auto file   = create_memory_stream();
auto stream = create_memory_stream();

if (is_packed_executable)
    file->read(sfxpack);
else
    file->read(sfxfull);

stream->write("@._P-DATA_.@", 12);
stream->write(4, 1);
stream->write(is_encrypted_flag, 1);
stream->write_data(caption, sizeof(caption));
stream->write_data(title, sizeof(title));
stream->write_data(comments, sizeof(comments));
stream->write_data(about_text, sizeof(about_text));
stream->write_data(button1_text, sizeof(button1_text));
stream->write_data(button1_url, sizeof(button1_url));
stream->write_data(button2_text, sizeof(button2_text));
stream->write_data(button2_url, sizeof(button2_url));
stream->write(file_count, 1);

for (auto x = 0u; x < file_count; x++)
{
    const auto file = files[x];

    stream->write_data(file->name, sizeof(file->name));
    stream->write(file->size, 4);
    stream->write_data(file->size_text, sizeof(file->size_text));
    stream->write_data(file->date, sizeof(file->date));
    stream->write_data(file->filter, sizeof(file->filter));
    stream->write(file->checksum, 4);
    stream->write(file->check_file_size, 1);
    stream->write(file->check_file_checksum, 1);
    stream->write(file->show_file_date, 1);
    stream->write(file->unknown00, 1);
    stream->write_data(file->unknown01, sizeof(file->unknown01));

    for (auto y = 0u; y < file->patch_count; y++)
    {
        const auto patch = file->patches[y];

        stream->write(patch->type, 1);
        stream->write(patch->offset, 4);
        stream->write_data(patch->data1, sizeof(patch->data1));

        if (patch->type > 0)
            stream->write_data(patch->data2, sizeof(patch->data2));
    }
}

// Append overlay to patch executable file..
file->append(stream);

// Inject icon into patch executable file if one was selected..
file->overwrite_icon(icon_info);

// Save and cleanup..
file->save(path);
file->release();
stream->release();

Hello CodeFission

CodeFission

CodeFission, (a play on words; fusion vs. fission), is a tool that decrypts, unpacks and extracts the information stored inside of CodeFusion generated patch files. With the information we figured out above, we can know understand how to read the overlay from a patch file and decipher its data back into normal data types. Since the data is mostly just serialized, it’s rather easy to unpack the overlay.

CodeFission is a command line utility that takes several arguments in order to function. These arguments define the patch file you wish to decrypt, unpack and extract the information from, the output file you wish to save the patch information to and the mode in which the data should be extracted. At this time, CodeFission supports exporting the information to the following types:

  • JSON - The patch information will be saved into a JSON file.
  • SQLite Database - The patch information will be saved into an SQLite database.
  • Text - The patch information will be saved into a flat text file.

Some example usages are:

.\codefission.exe -f .\testproj_decrypted.exe -o patch.json -m 1
.\codefission.exe -f .\testproj_encrypted.exe -o patch.db -m 2
.\codefission.exe -f .\testproj_decrypted.exe -o patch.txt -m 3

Detection and handling of encryption is entirely automatic based on the header flag.

Comments