Last active
November 18, 2023 16:47
-
-
Save castleberrysam/a0bb370382339acfaac461a2359d0f94 to your computer and use it in GitHub Desktop.
Some reverse engineered C++ code from the BYK8xx firmware update utility
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
extern char *fw_data; | |
extern int fw_len; | |
// used to hold the RunOnlyOneUpdateTools mutex | |
extern HANDLE dword_458908; | |
// used to hold the first byte pair after the firmware header | |
extern int dword_45868c; | |
// used to hold the second byte pair after the firmware header | |
extern int dword_458688; | |
// args: ecx, arg_0 | |
void load_resource(wchar_t **resource_ptr, char *fname) | |
{ | |
; | |
} | |
// Unknown is a superclass of CWinApp | |
void Unknown::sub_405C10(void) | |
{ | |
INITCOMMONCONTROLSEX icce; | |
icce.dwSize = 8; | |
icce.dwICC = 0xff; | |
InitCommonControlsEx(&icce); | |
this->InitInstance(); | |
// intialize some error strings on the stack... | |
OSVERSIONINFOW versionInfo; | |
versionInfo.dwOSVersionInfoSize = 0x114; | |
GetVersionExW(&versionInfo); | |
dword_458908 = CreateMutexW(NULL, FALSE, "RunOnlyOneUpdateTools"); | |
if(dword_458908 == NULL) { | |
return 1; | |
} | |
if(GetLastError() == ERROR_ALREADY_EXISTS) { | |
MessageBoxW(NULL, "Tool has already run!", "Warning", MB_ICONWARNING); | |
return 1; | |
} | |
char fname[260]; | |
struct AFX_MODULE_STATE *state = AfxGetModuleState(); | |
GetModuleFileNameW(state[8], fname, sizeof(fname)); | |
wchar_t *resource_ptr; | |
load_resource(&resource_ptr, fname); | |
// used after "if(file != NULL)", set inside only though | |
int var_98b4; | |
// esi | |
FILE *file = __wfopen(resource_ptr, "rb"); | |
if(file != NULL) { | |
int var_98cc; | |
loop: | |
var_98cc = 0; | |
_fread(&var_98cc, 1, 1, file); | |
if(var_98cc != 0x5a) {goto loop;} | |
var_98cc = 0; | |
_fread(&var_98cc, 1, 1, file); | |
if(var_98cc != 0xa5) {goto loop;} | |
var_98cc = 0; | |
_fread(&var_98cc, 1, 4, file); | |
if(((var_98cc >> 0) & 0xff) != 0x53) {goto loop;} | |
if(((var_98cc >> 8) & 0xff) != 0x49) {goto loop;} | |
if(((var_98cc >> 16) & 0xff) != 0x4e) {goto loop;} | |
if(((var_98cc >> 24) & 0xff) != 0x4f) {goto loop;} | |
short var_98c0; | |
_fread(&var_98c0, 1, 2, file); | |
dword_45868c = ((var_98c0 & 0xff) << 8) + (var_98c0 >> 8); | |
short var_98c4; | |
_fread(&var_98c4, 1, 2, file); | |
dword_458688 = ((var_98c4 & 0xff) << 8) + (var_98c4 >> 8); | |
short var_98c8; | |
_fread(&var_98c8, 1, 2, file); | |
fw_len = ((var_98c8 & 0xff) << 8) + (var_98c8 >> 8); | |
// edi | |
fw_data = malloc(fw_len); | |
memset(fw_data, 0x00, fw_len); | |
_fread(fw_data, 1, fw_len, file); | |
_fread(&var_98b4, 1, 4, file); | |
_fclose(file); | |
} | |
sub_402FF0(&var_98b4); | |
this->SetRegistryKey("SH68F073"); | |
// some dialog stuff... | |
return 0; | |
} | |
void sub_402FF0(int arg_0) | |
{ | |
int eax = fw_len; | |
if(eax < 0) {eax += 3;} | |
int edi = eax / 4; | |
eax = edi * 4; | |
// esi | |
int[] buf = new int[edi]; | |
char *ptr = fw_data; | |
for(int ecx=0;ecx<edi;++i) { | |
buf[ecx] = (ptr[0] << 24) + (ptr[1] << 16) + (ptr[2] << 8) + ptr[3]; | |
ptr += 4; | |
} | |
int eax = fw_len; | |
if(eax < 0) {eax += 7;} | |
eax /= 8; | |
char *ebx = buf; | |
for(;eax>0;--eax) { | |
sub_402F50(ebx, arg_0); | |
ebx += 8; | |
} | |
char *ecx = fw_data; | |
for(int eax=0;eax<edi;++eax) { | |
ecx[0] = buf[(eax*4)+3]; | |
ecx[1] = buf[(eax*4)+2]; | |
ecx[2] = buf[(eax*4)+1]; | |
ecx[3] = buf[(eax*4)+0]; | |
ecx += 4; | |
} | |
delete[] buf; | |
} | |
// args: arg_0, eax | |
void sub_402F50(unsigned int *ebx, unsigned char *eax) | |
{ | |
unsigned char byte0 = eax[0]; | |
unsigned char byte1 = eax[1]; | |
unsigned char byte2 = eax[2]; | |
unsigned char byte3 = eax[3]; | |
unsigned int int0 = ebx[0]; | |
unsigned int int1 = ebx[1]; | |
unsigned int edx = 0xc6ed3720; | |
for(int esi=32;esi>0;--esi) { | |
unsigned int edi, ebx; | |
edi = byte3 + (int0 >> 5); | |
ebx = byte2 + (int0 << 4); | |
edi ^= ebx; | |
edi ^= edx + int0; | |
int1 -= edi; | |
edi = byte0 + (int1 << 4); | |
ebx = byte1 + (int1 >> 5); | |
edi ^= ebx; | |
edi ^= edx + int1; | |
int0 -= edi; | |
edx += 0x61c89647; | |
} | |
ebx[0] = int0; | |
ebx[1] = int1; | |
} | |
// Used for sending data | |
// args: arg_0, arg_4, arg_8, arg_C, ecx (this) | |
void HANDLE::fw_upload(arg_0, arg_4, arg_8, arg_C) | |
{ | |
// ebx | |
char[] buf = new char[arg_8]; | |
buf[0] = 5; | |
buf[1] = 0x57; | |
buf[2] = 0; | |
buf[3] = 0; | |
buf[4] = arg_C & 0xff; | |
buf[5] = arg_C >> 8; | |
if(HidD_SetFeature(this, buf, sizeof(buf)) == 0) { | |
delete[] buf; | |
return 0; | |
} | |
// ebp | |
char[] buf2 = new char[2048+2]; | |
memset(buf2, 0x00, sizeof(buf2)); | |
buf2[0] = 6; | |
buf2[1] = 0x77; | |
// reset progress bar | |
SendMessageW(..., 0x402, 0, NULL); | |
if(arg_C < 0) {arg_C += 2047;} | |
int num_pages = arg_C / 2048; | |
char big_buf[2048]; | |
for(int page=0;page<num_pages;++page) { | |
memset(big_buf, 0x00, sizeof(big_buf)); | |
int offset = page * 2048; | |
int size = 2048; | |
if(offset + size > fw_len) { | |
size = fw_len - offset; | |
} | |
memcpy(big_buf, fw_data+offset, size); | |
if(page == 0) { | |
((int *) big_buf)[0] = 0; | |
} | |
memcpy(&buf2[2], big_buf, size); | |
if(HidD_SetFeature(arg_4, buf2, sizeof(buf2)) == 0) { | |
delete[] buf; | |
delete[] buf2; | |
return 0; | |
} | |
// update progress bar | |
SendMessageW(..., 0x402, ..., NULL); | |
} | |
// restart upload at base addr | |
HidD_SetFeature(this, buf, sizeof(buf)); | |
// resend first page of fw_data?? | |
int *str = (int *) fw_data; | |
int *dst = (int *) (buf2 + 2); | |
for(int i=0;i<512;++i) { | |
dst[i] = ptr[i]; | |
} | |
HidD_SetFeature(arg_4, buf2, sizeof(buf2)); | |
delete[] buf2; | |
delete[] buf; | |
return 1; | |
} | |
// Used for reading back data | |
// args: arg_0, arg_4, arg_8, ecx, edx | |
void HANDLE::fw_verify(arg_0, arg_4, arg_8) | |
{ | |
int edi = edx; | |
// ebp | |
char[] buf = new char[ecx]; | |
buf[0] = 5; | |
buf[1] = 0x52; | |
buf[2] = 0; | |
buf[3] = 0; | |
buf[4] = arg_8 & 0xff; | |
buf[5] = arg_8 >> 8; | |
if(HidD_SetFeature(edi, buf, sizeof(buf)) == 0) { | |
delete[] buf; | |
return 0; | |
} | |
// edi | |
char[] buf2 = new char[2048+2]; | |
memset(buf2, 0x00, 2048+2); | |
buf2[0] = 6; | |
buf2[1] = 0x72; | |
// reset progress bar | |
SendMessageW(..., 0x402, 0, NULL); | |
if(arg_8 < 0) {arg_8 += 2047;} | |
int num_pages = arg_8 / 2048; | |
char big_buf[2048]; | |
int offset = 0; | |
for(int page=0;page<num_pages;++page) { | |
if(HidD_GetFeature(arg_4, buf2, sizeof(buf2)) == 0) { | |
delete[] buf; | |
delete[] buf2; | |
return 0; | |
} | |
// update progress bar | |
SendMessageW(..., 0x402, ..., NULL); | |
memset(big_buf, 0x00, sizeof(big_buf)); | |
int size = 2048; | |
if(offset + 2048 > fw_len) { | |
size = fw_len - offset; | |
} | |
memcpy(big_buf, fw_data+offset, size); | |
int index = 0; | |
while(size >= 4) { | |
int val0 = ((int *) big_buf)[index/4]; | |
int val1 = ((int *) (buf2+2))[index/4]; | |
if(val0 != val1) {goto finer;} | |
index += 4; | |
size -= 4; | |
} | |
if(size == 0) { | |
offset += 2048; | |
continue; | |
} | |
finer: | |
char val0 = big_buf[index]; | |
char val1 = buf2[2+index]; | |
if(val0 != val1) { | |
delete[] buf; | |
delete[] buf2; | |
return 0; | |
} | |
--size; | |
++index; | |
if(size == 0) { | |
offset += 2048; | |
continue; | |
} | |
val0 = big_buf[index]; | |
val1 = buf2[2+index]; | |
if(val0 != val1) { | |
delete[] buf; | |
delete[] buf2; | |
return 0; | |
} | |
--size; | |
++index; | |
if(size == 0) { | |
offset += 2048; | |
continue; | |
} | |
val0 = big_buf[index]; | |
val1 = buf2[2+index]; | |
if(val0 != val1) { | |
delete[] buf; | |
delete[] buf2; | |
return 0; | |
} | |
--size; | |
++index; | |
if(size == 0) { | |
offset += 2048; | |
continue; | |
} | |
val0 = big_buf[index]; | |
val1 = buf2[2+index]; | |
if(val0 != val1) { | |
delete[] buf; | |
delete[] buf2; | |
return 0; | |
} | |
} | |
delete[] buf; | |
delete[] buf2; | |
Sleep(100); | |
return 1; | |
} | |
// Used for burning in sent data | |
// args: arg_0, eax | |
void fw_burn(arg_0) | |
{ | |
int edi = eax; | |
// esi | |
char[] buf = new char[6]; | |
buf[0] = 5; | |
buf[1] = 0x52; | |
buf[2] = 0x80; | |
buf[3] = 0xff; | |
buf[4] = 8; | |
buf[5] = 0; | |
HidD_SetFeature(edi, buf, sizeof(buf)); | |
buf[0] = 5; | |
buf[1] = 0x72; | |
buf[2] = 0; | |
buf[3] = 0; | |
buf[4] = 0; | |
buf[5] = 0; | |
HidD_GetFeature(edi, buf, sizeof(buf)); | |
// eax, arg_0 | |
int val0 = (buf[4] << 8) | buf[5]; | |
// ebx | |
int val1 = (buf[2] << 8) | buf[3]; | |
HidD_GetFeature(edi, buf, sizeof(buf)); | |
buf[0] = 5; | |
buf[1] = 0x65; | |
buf[2] = 0xff; | |
buf[3] = 0; | |
buf[4] = 0; | |
buf[5] = 0; | |
HidD_SetFeature(edi, buf, sizeof(buf)); | |
Sleep(200); | |
buf[0] = 5; | |
buf[1] = 0x57; | |
buf[2] = 0x80; | |
buf[3] = 0xff; | |
buf[4] = 8; | |
buf[5] = 0; | |
HidD_SetFeature(edi, buf, sizeof(buf)); | |
buf[0] = 5; | |
buf[1] = 0x77; | |
buf[2] = val1 >> 8; | |
buf[3] = val1 & 0xff; | |
buf[4] = val0 >> 8; | |
buf[5] = val0 & 0xff; | |
HidD_SetFeature(edi, buf, sizeof(buf)); | |
Sleep(100); | |
buf[0] = 5; | |
buf[1] = 0x77; | |
buf[2] = arg_0[0x42c]; | |
buf[3] = 0; | |
buf[4] = arg_0[0x424] >> 8; | |
buf[5] = arg_0[0x424] & 0xff; | |
int ret = HidD_SetFeature(edi, buf, sizeof(buf)); | |
delete[] buf; | |
return (ret != 0) ? 1 : 0; | |
} | |
void Unknown::sub_4014E0(void) | |
{ | |
printf("Open device...\n"); | |
LPCWSTR fname0 = "???"; | |
LPCWSTR fname1 = "???"; | |
// edi = file0, ebx = file1 | |
HANDLE file0 = CreateFileW(fname0, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); | |
HANDLE file1 = CreateFileW(fname1, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, | |
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); | |
if(file0 == -1) { | |
printf("Open device fail\n"); | |
return 2; | |
} | |
printf("Open is Ok\n"); | |
HIDD_ATTRIBUTES attrs; | |
attrs.Size = 12; | |
HidD_GetAttributes(file0, &attrs); | |
PHIDP_PREPARSED_DATA ppData; | |
HidD_GetPreparsedData(file0, ppData); | |
HIDP_CAPS caps; | |
HidP_GetCaps(ppData, &caps); | |
HidD_FreePreparsedData(ppData); | |
// ebp | |
char[] buf = new char[caps.FeatureReportByteLength]; | |
memset(buf, 0x45, sizeof(buf)); | |
buf[0] = 5; | |
if(HidD_SetFeature(file1, buf, sizeof(buf)) == 0) { | |
printf("Erase fail\n"); | |
return 2; | |
} | |
printf("Erasing...\n"); | |
Sleep(2000); | |
int eax = fw_len; | |
int ecx = eax & 0x800007ff; | |
int var_78 = eax; | |
if(var_78 < 0) { | |
ecx = ((ecx - 1) & 0xfffff800) + 1; | |
if(ecx != 0) {goto label;} | |
} else if(var_78 != 0) { | |
label: | |
if(eax < 0) {eax += 2047;} | |
eax = ((eax / 2048) + 1) * 2048; | |
var_78 = eax; | |
} | |
int counter = 0; | |
while(true) { | |
// args: arg_0 = this, arg_4 = file0, arg_8 = sizeof(buf), arg_C = var_78, ecx = file1 | |
if(file1.fw_upload(this, file0, sizeof(buf), var_78) != 0) { | |
if(counter < 5) { | |
break; | |
} else { | |
error: | |
CloseHandle(file0); | |
CloseHandle(file1); | |
delete[] buf; | |
printf("Send data fail\n"); | |
return 2; | |
} | |
} else { | |
if(counter < 5) { | |
++counter; | |
} else { | |
goto error; | |
} | |
} | |
} | |
counter = 0; | |
while(true) { | |
// args: arg_0 = this, arg_4 = file0, arg_8 = var_78, ecx = sizeof(buf), edx = file1 | |
if(file1.fw_verify(this, file0, var_78) != 0) { | |
if(counter < 10) { | |
break; | |
} else { | |
error: | |
CloseHandle(file0); | |
CloseHandle(file1); | |
delete[] buf; | |
printf("Read back fail\n"); | |
return 2; | |
} | |
} else { | |
if(counter < 10) { | |
++counter; | |
} else { | |
goto error; | |
} | |
} | |
} | |
// args: arg_0 = this, eax = file1 | |
if(fw_burn(this) == 0) { | |
CloseHandle(file0); | |
CloseHandle(file1); | |
delete[] buf; | |
printf("Burn fail\n"); | |
return 2; | |
} | |
memset(buf, 0x55, sizeof(buf)); | |
buf[0] = 5; | |
if(HidD_SetFeature(file1, buf, sizeof(buf)) == 0) { | |
printf("Burn fail\n"); | |
CloseHandle(file0); | |
CloseHandle(file1); | |
delete[] buf; | |
return 2; | |
} | |
CloseHandle(file0); | |
CloseHandle(file1); | |
delete[] buf; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, I have started looking at the firmware on my "RK61RGB ISO Return Keyboard" PID 0065; The firmware flash tool also seems to contain the same processor name "SH68F073", could it possibly be the same chip in both the byk8xx and byk9xx?