FreeFileSync: Connection Limits and the Tamper Check
About the author. I’m Colin Xiao — an independent reverse engineer, mostly working solo on contract jobs. I dig into compiled code of every kind, including but not limited to: Android and iOS apps, x86/x64/ARM native binaries, packers and obfuscators, DRM and license checks, network protocols and APIs, crypto and signature algorithms, malware, game binaries, and embedded/IoT firmware. I also handle large-scale data collection and vulnerability research. If you have any project in mind, I’d be glad to take it on — whatever it is, as long as it’s within my wheelhouse. Just reach out. You can reach me on X at @colinxiao_lab or on Telegram at https://t.me/ColinXiao666.
This research is published for educational and defensive purposes. The target sample is anonymized throughout.
FreeFileSync: Connection Limits and the Tamper Check
FreeFileSync ships its source openly, but the official binaries also contain code that isn’t in the public tree — including a donation-gated performance limit and an integrity check. This is a walkthrough of both.
Breaking the performance limit
The parallel-connection control is disabled in the UI:

Reading the open-source code leads to the key constructor:
CloudSetupDlg::CloudSetupDlg(wxWindow* parent, Zstring& folderPathPhrase, Zstring& sftpKeyFileLastSelected, size_t& parallelOps, bool canChangeParallelOp) :
CloudSetupDlgGenerated(parent),
sftpKeyFileLastSelected_(sftpKeyFileLastSelected),
folderPathPhraseOut_(folderPathPhrase),
parallelOpsOut_(parallelOps)
Inside the body:
m_spinCtrlConnectionCount->SetValue(parallelOps);
m_spinCtrlConnectionCount->Disable(); // this disables the control
m_staticTextConnectionCountDescr->Hide();
m_spinCtrlChannelCountSftp->Disable();
m_buttonChannelCountSftp ->Disable();
Dynamic debugging locates the spot:

Nop the call and the control becomes enabled:

The integrity check
Apply the patch and run it — a verification dialog appears, and clicking OK exits the program:

Debugging from that message leads to the verification logic; the WV error string gives the position away:

FreeFileSync’s official build contains code absent from the open-source version, and it uses a simple string-obfuscation function:

IDA’s pseudocode:
char *__fastcall decodestring(char *outstr, char *inputstr, int key)
{
char *v3; // r9
int v5; // r8d
int v6; // ebx
char *v7; // rcx
char *v8; // r8
char *v9; // r10
char *result; // rax
v3 = inputstr;
v5 = key % 95;
v6 = v5 + 95;
if ( v5 >= 0 )
v6 = v5;
if ( *((_QWORD *)inputstr + 3) <= 0xFui64 )
{
v7 = inputstr;
v8 = inputstr;
}
else
{
v7 = *(char **)inputstr;
inputstr = *(char **)inputstr;
v8 = (char **)v3;
}
v9 = &inputstr[((_QWORD *)v3 + 2)];
if ( v8 != v9 )
{
do
{
if ( (unsigned __int8)(*v7 - 32) <= 0x5Eu )
*v7 = (*v7 + v6 - 32) % 95 + 32;
++v7;
} while ( v7 != v9 );
}
*(_OWORD *)outstr = 0i64;
*((_QWORD *)outstr + 2) = 0i64;
*((_QWORD *)outstr + 3) = 0i64;
*(_OWORD *)outstr = *(_OWORD *)v3;
*((_OWORD *)outstr + 1) = *((_OWORD *)v3 + 1);
*((_QWORD *)v3 + 3) = 15i64;
*((_QWORD *)v3 + 2) = 0i64;
*v3 = 0;
result = outstr;
*((_QWORD *)v3 + 3) = 15i64;
return result;
}
Here’s the cleaned-up version, in full:
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
typedef struct {
union {
char* ptr;
char local_buf[16];
};
size_t size;
size_t capacity;
} EncryptedString;
int64_t decodestring(int64_t dest_ptr, EncryptedString* src, int key)
{
int shift = key % 95;
if (shift < 0)
{
shift += 95;
}
char* data_start;
if (src->capacity <= 15)
{
data_start = src->local_buf;
}
else {
data_start = src->ptr;
}
size_t length = src->size;
char* data_end = data_start + length;
for (char* p = data_start; p < data_end; ++p)
{
unsigned char c = *p;
if (c >= 32 && c <= 126)
{
c = (c - 32 + shift) % 95;
*p = (char)(c + 32);
}
}
EncryptedString* dest = (EncryptedString*)dest_ptr;
*dest = *src;
src->capacity = 15;
src->size = 0;
src->local_buf[0] = '\0';
return(dest_ptr);
}
int main(void)
{
char out1[256] = { 0 };
char out2[256] = { 0 };
char p1[] = {
0x5E, 0x70, 0x75, 0x5D, 0x6C, 0x79, 0x70, 0x6D, 0x21, 0x5B, 0x79, 0x7C, 0x7A, 0x7B, 0x00, 0x00,
0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
char p2[] = {
0x5F, 0x71, 0x76, 0x7C, 0x7A, 0x7D, 0x7B, 0x7C, 0x36, 0x6C, 0x74, 0x74, 0x00, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
decodestring(out1, p1, 0xFFFFFFF9);
decodestring(out2, p2, 0xFFFFFFF8);
printf("%s\n", out1);
printf("%s\n", out2);
return(0);
}
The output:

WinVerifyTrust
Wintrust.dll
So the check uses WinVerifyTrust to validate the binary’s signature and decide whether it’s been modified. Make that function return a valid result — or patch the following branch — and the program runs normally, with the parallel-performance control working as intended.

Colin Xiao — I take on contract reverse-engineering work, and writeups like this are how I show what I can do. If you need help with anything in this space — including but not limited to the areas I cover above — I’m available. No project is too big or too small — if it’s reverse engineering and I can do it, I’ll take it. DM me on X (@colinxiao_lab) or Telegram (@ColinXiao666).
Get in touch