Here is some code from applauncher.exe, which deals with doing the CRC verification. It appears that I was right about doACRC in this post:
https://www.eevblog.com/forum/thermal-imaging/flir-e4-wifi-resolution-and-menu-hack-thread/msg1181686/#msg1181686applauncher.dat
# doCRC FlashBFS\system\common_dll.dll 1276928 1802841112
....
# doACRC FlashBFS\system\common_dll.dll 1276928 639260284
signed int __fastcall sub_11B68(const wchar_t *a1)
{
const wchar_t *v1; // r4@1
signed int v2; // r9@1
signed int v3; // r5@1
DWORD v4; // r0@1
size_t v5; // r6@1
void *v6; // r7@3
FILE *v7; // r0@5
FILE *v8; // r8@5
const char *v9; // r6@9
char *v10; // r0@10
DWORD v11; // r4@12
int v12; // r0@13
const char *v13; // r6@18
char *v14; // r0@19
DWORD v15; // r4@21
int v16; // r0@22
size_t v18; // [sp+4h] [bp-34Ch]@7
int v19; // [sp+8h] [bp-348h]@11
char v20; // [sp+Ch] [bp-344h]@21
char v21; // [sp+14h] [bp-33Ch]@12
char v22; // [sp+30h] [bp-320h]@11
WCHAR Buffer; // [sp+130h] [bp-220h]@12
int v24; // [sp+330h] [bp-20h]@1
v1 = a1;
v24 = dword_161A0;
v2 = 0;
v3 = 0;
v4 = sub_1181C(a1);
v5 = v4;
if ( !v4 )
goto LABEL_2;
v6 = operator new(v4 + 1);
if ( !v6 )
{
sub_14994(v24);
return 3;
}
*(_BYTE *)v6 = 0;
v7 = wfopen(v1, L"rb");
v8 = v7;
if ( !v7 )
{
NKDbgPrintfW(L"verifyCRC - cannot open %s\r\n", v1);
LABEL_2:
sub_14994(v24);
return 1;
}
v18 = fread(v6, 1u, v5, v7);
if ( v18 != v5 )
v3 = 4;
fclose(v8);
v9 = (const char *)v6;
while ( !v3 )
{
v10 = strstr(v9, "# doCRC ");
if ( !v10 )
break;
v9 = v10 + 1;
if ( sscanf(v10, "# doCRC %s %u %u", &v22, &v18, &v19) == 3 )
{
wsprintfW(&Buffer, L"%S", &v22);
v11 = sub_1181C(&Buffer);
sub_14250((int)&v21, 1);
if ( v18 == v11 )
{
sub_125BC((int)&v21, &v22);
v12 = sub_142B4((int)&v21, (int)&v18, 4u);
if ( v12 != v19 )
{
NKDbgPrintfW(L"%S [CRC]\r\n", &v22);
v3 = 5;
}
}
else
{
NKDbgPrintfW(L"%S [size]\r\n", &v22);
v3 = 6;
}
sub_12978(&v21);
}
}
v13 = (const char *)v6;
if ( v3 )
goto LABEL_33;
do
{
v14 = strstr(v13, "# doACRC ");
if ( !v14 )
break;
v2 = 1;
v13 = v14 + 1;
if ( sscanf(v14, "# doACRC %s %u %u", &v22, &v18, &v19) == 3 )
{
wsprintfW(&Buffer, L"%S", &v22);
v15 = sub_1181C(&Buffer);
sub_12898((int)&v20, 0x4C11DB7);
if ( v18 == v15 )
{
sub_125BC((int)&v20, &v22);
v16 = sub_12844((int)&v20, &v18, 4);
if ( v16 != v19 )
{
NKDbgPrintfW(L"%S [CRC]\r\n", &v22);
v3 = 5;
}
}
else
{
NKDbgPrintfW(L"%S [size]\r\n", &v22);
v3 = 6;
}
sub_127AC(&v20);
}
}
while ( !v3 );
if ( !v2 )
LABEL_33:
v3 = 7;
operator delete(v6);
sub_14994(v24);
return v3;
}
Here are the functions 2 calls up the stack, where you can see when the integrity check is enforced:
v18 = CreateFileW(L"FAD1:", 0, 0, 0, 3u, 0x80u, 0);
if ( DeviceIoControl(v18, 0x800040C0, 0, 0, &OutBuf, 0x18u, 0, 0) )
{
if ( v35 )
{
// This is one liner, calling sub_11B68, where the CRC check is done.
v4 =
sub_11E1C(v15);
NKDbgPrintfW(L"Integrity: %d\r\n", v4);
}
else
{
NKDbgPrintfW(L"No integrity check necessary\r\n");
}
}
BOOL __fastcall sub_11E1C(wchar_t *a1)
{
wchar_t *v1; // r4@1
v1 = a1;
return sub_11880(a1) && !sub_11B68(v1);
}
signed int __fastcall sub_11E5C(signed int a1, int a2)
{
int v2; // r5@1
signed int v3; // r6@1
BOOL v4; // r7@1
bool v5; // zf@2
signed int v6; // r3@5
int v7; // r0@7
int v8; // r4@7
int v9; // r8@7
int v10; // r3@10
signed int v12; // r5@16
const char *v13; // r0@21
const wchar_t *v14; // r1@30
wchar_t *v15; // r6@34
FILE *v16; // r0@34
const char *v17; // r0@37
HANDLE v18; // r4@41
DWORD v19; // r0@45
HDC v20; // r4@51
FILE *v21; // r6@56
int v22; // r4@57
int v23; // r7@57
int v24; // [sp+18h] [bp-A70h]@1
HKEY hKey; // [sp+1Ch] [bp-A6Ch]@1
DWORD cbData; // [sp+20h] [bp-A68h]@3
int v27; // [sp+24h] [bp-A64h]@7
DWORD dw; // [sp+28h] [bp-A60h]@1
DWORD Type; // [sp+2Ch] [bp-A5Ch]@22
CHAR v30[4]; // [sp+30h] [bp-A58h]@51
struct _PROCESS_INFORMATION v31; // [sp+34h] [bp-A54h]@49
HANDLE hObjects; // [sp+44h] [bp-A44h]@49
HANDLE v33; // [sp+48h] [bp-A40h]@51
char OutBuf; // [sp+4Ch] [bp-A3Ch]@41
int v35; // [sp+50h] [bp-A38h]@42
wchar_t pszImageName; // [sp+64h] [bp-A24h]@57
wchar_t Data[1024]; // [sp+264h] [bp-824h]@17
int v38; // [sp+A64h] [bp-24h]@1
v2 = a2;
v3 = a1;
v38 = dword_161A0;
hKey = 0;
v4 = 1;
dw = 0;
if ( !KernelIoControl(16850952, 0, 0, &v24) )
goto LABEL_76;
v5 = v24 == 1;
if ( v24 == 1 )
v5 = cbData == 4;
if ( v5 )
v6 = 1;
else
LABEL_76:
v6 = 0;
v24 = v6;
v7 = KernelIoControl(16850988, 0, 0, &v27);
v8 = v24;
v9 = v7;
v10 = v7 && v27 && !v24;
v27 = v10;
if ( v3 < 2 )
{
printf("Usage: applauncher [options]\n-f <filename> Execute commands in file <filename>\n-r Execute file specified by registry setting.\n(number) Automatic mode (OS internal).\n");
sub_14994(v38);
return 1;
}
if ( v3 != 2 )
{
if ( v3 != 3 || wcscmp(L"-f", *(const wchar_t **)(v2 + 4)) )
{
v13 = "Bad Argument(s)! Use \"applauncher\" for help.\n";
goto LABEL_72;
}
v14 = *(const wchar_t **)(v2 + 8);
v12 = 0;
wcscpy(Data, v14);
goto LABEL_31;
}
if ( !wcscmp(L"-r", *(const wchar_t **)(v2 + 4)) )
{
v12 = 0;
}
else
{
swscanf(*(const wchar_t **)(v2 + 4), L"%[0-9]", &Data[512]);
if ( wcscmp(&Data[512], *(const wchar_t **)(v2 + 4)) )
{
v13 = "Bad Argument! Use \"applauncher\" for help.\n";
goto LABEL_72;
}
swscanf(*(const wchar_t **)(v2 + 4), L"%d", &dw);
v12 = 1;
}
if ( !RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\FLIR Systems\\Applauncher", 0, 0, &hKey) )
{
cbData = 510;
if ( RegQueryValueExW(hKey, L"LaunchFile", 0, &Type, (LPBYTE)Data, &cbData) )
goto LABEL_39;
if ( Type != 1 )
goto LABEL_39;
cbData = 510;
if ( RegQueryValueExW(hKey, L"LaunchFileAlt", 0, &Type, (LPBYTE)&Data[256], &cbData) || Type != 1 )
goto LABEL_39;
RegCloseKey(hKey);
v8 = v24;
LABEL_31:
if ( v12 )
{
Sleep(0x64u);
v8 = v24;
}
if ( v8 )
goto LABEL_77;
v15 = Data;
v16 = wfopen(Data, L"r");
if ( !v16 )
{
v15 = &Data[256];
v16 = wfopen(&Data[256], L"r");
if ( !v16 )
{
if ( !v12 )
{
v17 = "Failed to open the launch specification file. Aborting!\n";
LABEL_38:
printf(v17);
LABEL_39:
RegCloseKey(hKey);
goto LABEL_73;
}
goto LABEL_40;
}
}
fclose(v16);
v18 = CreateFileW(L"FAD1:", 0, 0, 0, 3u, 0x80u, 0);
if ( DeviceIoControl(v18, 0x800040C0, 0, 0, &OutBuf, 0x18u, 0, 0) )
{
if ( v35 )
{
v4 = sub_11E1C(v15);
NKDbgPrintfW(L"Integrity: %d\r\n", v4);
}
else
{
NKDbgPrintfW(L"No integrity check necessary\r\n");
}
}
else
{
v19 = GetLastError();
NKDbgPrintfW(L"FAD call fails:%d hndl:%d err:%d\r\n", 0, v18, v19);
}
CloseHandle(v18);
if ( v24 )
goto LABEL_77;
if ( !v9 )
goto LABEL_78;
if ( !v4 )
goto LABEL_54;
NKDbgPrintfW(L"APPLAUNCHER: Starting usb charge App \r\n");
hObjects = CreateEventW(0, 0, 0, L"ChargeAppFinished");
if ( CreateProcessW(L"ChargeApp.exe", 0, 0, 0, 0, 0, 0, 0, 0, &v31) && v27 )
{
*(_DWORD *)v30 = 2;
v20 = CreateDCW(0, 0, 0, 0);
CreateProcessW(L"cmd.exe", L"/R", 0, 0, 0, 0, 0, 0, 0, &v31);
v33 = v31.hProcess;
WaitForMultipleObjects(2u, &hObjects, 0, 0xFFFFFFFF);
NKDbgPrintfW(L"APPLAUNCHER: Usb charging finished\r\n");
ExtEscape(v20, 100037, 4, v30, 0, 0);
}
CloseHandle(v31.hProcess);
CloseHandle(v31.hThread);
if ( v24 )
{
LABEL_77:
CreateProcessW(L"cmd.exe", L"/R", 0, 0, 0, 0, 0, 0, 0, &v31);
}
else
{
LABEL_78:
if ( !v4 )
{
LABEL_54:
if ( !v12 )
{
v17 = "APPLAUNCHER: Refuses to run launch specification file. Aborting!\r\n";
goto LABEL_38;
}
LABEL_40:
SignalStarted(dw);
goto LABEL_39;
}
v21 = wfopen(v15, L"r");
while ( !feof(v21) )
{
fwscanf(v21, L"%[\t\v\n\r\f]", &pszImageName);
v22 = fwscanf(v21, L"%[^ #\t\v\n\r\f]", &pszImageName);
v23 = fwscanf(v21, L"%[^#\t\v\n\r\f]", &Data[768]);
if ( v22 > 0 && wcslen(&pszImageName) >= 1 )
{
if ( !v27 || wcsicmp(&pszImageName, L"cmd") )
{
if ( v23 <= 0 )
CreateProcessW(&pszImageName, 0, 0, 0, 0, 0, 0, 0, 0, &v31);
else
CreateProcessW(&pszImageName, &Data[768], 0, 0, 0, 0, 0, 0, 0, &v31);
continue;
}
NKDbgPrintfW(L"APPLAUNCHER: Not starting duplicate cmd.exe \r\n");
}
fwscanf(v21, L"%[^\t\v\n\r\f]", &pszImageName);
}
}
if ( v12 )
SignalStarted(dw);
goto LABEL_73;
}
if ( !v12 )
{
v13 = "Failed to open registry settings. Aborting!\n";
LABEL_72:
printf(v13);
}
LABEL_73:
sub_14994(v38);
return 0;
}
Basically it is doing the old CRC verification (first checks the file size) and then another verification, which appears to be a CRC32, based on this:
sub_12898((int)&v20,
0x4C11DB7);
A quick check with Google for 0x04C11DB7 shows that it is the Normal Polynomial representation for CRC-32 (
https://en.wikipedia.org/wiki/Cyclic_redundancy_check).
So in order for the old hack method to work, either the common_dll.dll patch should be made in such a way that it is not detected by both CRC checks (although both have weak points, not sure how easy it is to circumvent both at the same time), or the applauncher.dat is modified to remove the doACRC lines (if can be modified, we could have removed the old doCRC, so I guess this is not an easy option)
I don't have much knowledge and time for this, so this is the best I can do to help.