Quote:
Originally Posted by bricker
incredible. how does this work on a technical level? how did you find what to replace in the binary?
|
After identifying kindle_browser as the primary binary, I disassembled it using Ghidra. I searched for the string "azw3", because the browser must have that string in memory at some point in order to compare whether the file you are downloading matches one of the allowed extensions. I searched for x-refs to the string to find this code:
Code:
FUN_00036b7e(auStack_6c,".azw1");
FUN_00036b7e(auStack_60,".azw2");
FUN_00036b7e(auStack_54,".azw3");
FUN_00036b7e(auStack_48,&DAT_000323a4);
FUN_00036b7e(auStack_3c,".mobi");
FUN_00036b7e(auStack_30,&DAT_0002f676);
iVar10 = 0;
do {
if (iVar10 == 0x54) {
bVar1 = false;
goto LAB_0004d7d0;
}
base::BasicStringPiece<>::BasicStringPiece((char *)&uStack_90);
iVar7 = base::FilePath::MatchesExtension((GURL *)aFStack_84,uStack_90,uStack_8c);
iVar10 = iVar10 + 0xc;
} while (iVar7 == 0);
bVar1 = true;
LAB_0004d7d0:
which is essentially a for loop checking each extension to see if it matches, and if after checking all of them if it still hasn't matched, it sets the bVar1 to false, indicating our extension is not in the allowed list.
I patched it to:
Code:
FUN_00036b7e(auStack_6c,".azw1");
FUN_00036b7e(auStack_60,".azw2");
FUN_00036b7e(auStack_54,".azw3");
FUN_00036b7e(auStack_48,&DAT_000323a4);
FUN_00036b7e(auStack_3c,".mobi");
FUN_00036b7e(auStack_30,&DAT_0002f676);
iVar10 = 0;
do {
if (iVar10 == 0x54) {
bVar1 = true; <-- PATCH
goto LAB_0004d7d0;
}
base::BasicStringPiece<>::BasicStringPiece((char *)&uStack_90);
iVar7 = base::FilePath::MatchesExtension((GURL *)aFStack_84,uStack_90,uStack_8c);
iVar10 = iVar10 + 0xc;
} while (iVar7 == 0);
bVar1 = true;
LAB_0004d7d0:
so that in the case where no extension in the list matches, it still returns true instead of false.
old:
Code:
0004d7ce 00 25 movs r5,#0x0
new:
Code:
0004d7ce 01 25 movs r5,#0x1
Next, I searched for strings "http" and https", but the only thing I could find was this import from libchromium.so:
Code:
/* GURL::SchemeIsHTTPOrHTTPS() const */
undefined4 __thiscall GURL::SchemeIsHTTPOrHTTPS(GURL *this)
{
size_t sVar1;
int iVar2;
undefined4 uVar3;
sVar1 = strlen("http");
iVar2 = FUN_018d3db8(this,&DAT_00840f1b,sVar1);
if (iVar2 != 0) {
return 1;
}
sVar1 = strlen("https");
uVar3 = FUN_018d3db8(this,"https",sVar1);
return uVar3;
}
I tried patching it to:
Code:
/* GURL::SchemeIsHTTPOrHTTPS() const */
undefined4 __thiscall GURL::SchemeIsHTTPOrHTTPS(GURL *this)
{
size_t sVar1;
int iVar2;
undefined4 uVar3;
sVar1 = strlen("http");
iVar2 = FUN_018d3db8(this,&DAT_00840f1b,sVar1);
return 1; <-- PATCH
sVar1 = strlen("https");
uVar3 = FUN_018d3db8(this,"https",sVar1);
return uVar3;
}
We removed the if statement, and simply executed the return.
old:
Code:
018d3e04 08 b1 cbz this,LAB_018d3e0a
new:
The installation script does 3 things:
- Copies the browser binaries from system directories to a new directory in /mnt/us
- Patches them
- Updates /var/local/appreg.db so that the browser launch command executed when you open the browser from the GUI points to the new, patched browser instead.