anyone feel like this is an invitation to crack a game?
yes, even a bible game?
anyone feel like this is an invitation to crack a game?
yes, even a bible game?
there's definitely some way to make ghidra tell you the fill offset of the current instruction, but I can't remember it, so I go to Bytes view, select the next 32 bytes or so, and search the EXE in a hex editor:
Bingo, at 0x882B. Change to EB & save it out to BBCRACKD.EXE
@foone Do you often get games checking for this and introducing errors? I know CRPG Addict has had issues with cracked games where they would introduce problems if you bypassed the copy protection in the most obvious way
sticking 74 1D into https://shell-storm.org/online/Online-Assembler-and-Disassembler/, it tells us it's "je 0x1f" (JE is a synonym for JZ).
So stick JMP 0x1f into the assembler, and we get EB 1D back.
So we need to find that 74 in the binary and turn it into EB
naturally if you copy this program onto another disk (or a hard drive), all those sectors will be valid, so it'll fail the check.
Anyway that'd be a pain to replicate on a real disk or a virtual DOSBox hard drive.
So, lets just patch out the check, or more accurately, the consequences of the check.
at 1000:87eb we have 74 1d:
JZ LAB_1000_880a
LAB_1000_880a is after the print-uh-oh stuff, and it's jumping if the result of FUN_1000_8798 is non-NULL.
They pass in sector_num of 0x2ca.
So presumably on the original disks they did some special formatting (or manually marked that sector as bad?) so that sectors 0x2c9 and 0x2cb existed, but 0x2ca didn't.
FUN_1000_8798 seems to be the magic. It gets the current drive, then calls FUN_1000_8739.
FUN_1000_8739 in turn, calls a low-level BIOS disk drive call. Perfect chance to do some copy protection
Here we go. It gets passed a sector number, and it confirms that the sector doesn't exist, but the sector before and after it do.
(with a free disk subsystem reset and read of sector 1 in the middle)
Which leads us right to FUN_1000_87c7, containing this code:
STEP ONE: unpack with UNP.
UNP 4.12 Executable file restore utility, written by Ben Castricum, 07/22/96
Special version registered to Otto Stock, distribution prohibited.
processing file : ..\BB\BB.EXE
DOS file size : 73447
file-structure : executable (EXE)
EXE part sizes : header 512 bytes, image 72935 bytes, overlay 0 bytes
processed with : LINK V3.60, V3.64, V3.65 or V5.01.21 /EXEPACK
action : decompressing... done
new file size : 81792
writing to file : ..\BB\BB.EXE
Step two: loaded it in ghidra, do a string search. We find the "Oh, oh! This doesn't seem to be an original disk!" at 1fed:27cd. Since this is segmented, we can't just search for that string.
but we CAN do a scalar search for 0x27cd!
And we're in the game with no "YOU PIRATED THIS!" message.
Done.
this angel has no idea I just cracked their game
SHIT WHO TOLD THEM?
it's 8x8 fixed width (like an NES font!) so we don't need to extract widths from anywhere to make a death generator
and there at offset C13B in the decompressed EXE, we've got the font.
why would I hack one game when I could hack EVERY GAME ?
mwahahaha
I need to build me a tool to make this sort of research more automatic. I wanna give it a dozen copies of the game and have it tell me how many variants I have and what files are different, what dates are different, etc.
then I just run it on EVERY GAME I CAN FIND
much to do. unfortunately it's 6am. so it'll have to be done elsewhen.
I'm doing a little research into copies of this game online, and so far I've found three distinct versions:
1. a 1996-dated version
2. a 1996-dated version with a savegame from 2021 because someone checked it worked and accidentally put the savegame in the zip/rar they distributed
3. the same 1996 version, but with a 2009 date on the accidental save game.
also need to:
#1 figure out that FAT error. I'm in the wrong cluster or something.
#2 write a wrong-sector instead of a missing-sector. writing only 17 sectors per tracks might accidentally leave behind an un-erased 18th sector from the previous formatting, and that's gonna confuse everything
also I don't have a good way to get a stream image out of 86box (because it uses a format I don't have any other tools that support, 86f), so I'm gonna have to run the code on a real PC and then image the resulting disk. Yet another reason to fix my code for 720kb disks
I'm not 100% sure that disk file listing is original, but it seems to work. The game will ask you for different disks as you go around the program, and that seems to match
my version isn't exactly right, I was assuming 1.44mb disks. I need to recreate my tool but with 720kb in mind. Then I can make 3 disk images that'll work
I also need to put the cracked version up on the internet archive to play, natch
okay the disks need to look like this:
DISK1:
bb.exe
bb.ico
dat1
dat2
dat4
DISK2:
dat5
DISK3:
dat3
this site says it has some cracks for it. It'd be interesting to see how they work, but I don't have an account for them:
the angel wants me to insert disk #1.
man if I had a nickel for every time an angel talked to me about floppy disks...
this internet archive upload is technically mislabeled: it says it's the demo, but it's actually the full game: it's just stuck in demo mode because of the copy protection.
https://archive.org/details/BibleBuilderSW1992EverbrightEducational
this article confirms it came on 720kb 3.5" floppies or 1.2mb 5.25" floppies:
(there's CD copies on ebay. I ordered one, to see if they're using the same copy protection or if they came up with a different method/cracked it themselves)
https://www.tampabay.com/archive/1992/12/19/exploring-scriptures-electronically/
and this warez NFO says it came on 3 720k disks.
I (mostly) WIN
The game loaded with no "bad disk" complaints.
it then froze because of there being some files missing from the disk, but I don't actually have enough space to write them all. I'm not really sure why that is.
but that's a separate issue! the important thing is, I bypassed the copy protection without cracking it!
I probably have an off-by-one error in the FAT edits
nope, crashes scandisk as well. Shame.
lets see if I can copy files onto it
Sector not found writing drive A
Abort, Retry, Ignore, Fail?
WHAT DO YOU MEAN? IT'S MARKED BAD!
bingo! it fails to read sector 0x2CA but neighboring sectors are fine.
I wonder if it'll pass scandisk? Lemme mark the cluster bad first.
they go to 0x03a7: that's 17 sectors, like I was trying to write, but presumably they're showing as BAD because I put them in ENTIRELY THE WRONG PLACE
I told it to write to track 19h (dec 25)
but it's track DEC 19 that I was aiming for.
WHOOPS
BAD sectors start at 0x396? I was aiming for 0x02CA!
I might just have to write a program to check every sector on the disk, to confirm where I'm overwriting
said program is now runnign
this would be easier to deal with if I didn't have to juggle 2 emulators, one of which has debugging and one of which supports flux-level disks
well that's probably not a great sign
I wrote a simple test program to try reading the 3 affected sectors, and... they're all successfully read on my disk. I think I have YET ANOTHER off-by-one error, like I'm reformatting the wrong track.
SCANDISK really doesn't like this disk. it's sitting here forever looking for a sector that doesn't exit
20 bad sectors? No, I fucked up BAD somewhere.
I had off by one errors in two directions! but sadly they didn't cancel each other out.
I may have created the disk
meh this is a pain. to the NASM!
note to self: before you try to CALL a function, make sure you have a stack first.
arg. I should have guessed debug.com has a tiny tiny input buffer, and it can't handle being asked to hold 68 bytes at once
dang it, I started putting data into DEBUG.COM, then I realized I have no way to paste in the data I'm generating in a python script.
I mean, not without designing a new keyboard...
keyboard written (or rather, a script for my scriptable automation keyboard project). it generates a disk format or passing to int 13 ah=5, but once it generates it it then types it in at the keyboard. So I'll run it, switch to 86box, and let the keyboardscript type it into DEBUG.COM
okay sector 2ca is on CHS 19/1/12
meaning this is a trickier compression than I thought: They left out a sector! it's just not on the disk.
They had to do this in the formatting step!
looking into the freedos FORMAT source. maybe I can easily modify it to skip over 0x2CA
oooooh! I'm totally wrong.
this is doing an int 25 DOS 1+ - ABSOLUTE DISK READ.
I set a cluster to BAD.
This thing doesn't even USE clusters! it's raw sector access!
1 bad sector, eh? hopefully it's the right one!
Doesn't work. Back to DOSBox so I can have a debugger!
(I'm trying to recreate the copy protection)
you might notice I did DAT1, DAT2, DAT3, and then DAT5: DAT4 is completely different and apparently part of the copy protection?
hey @dosnostalgic: isn't there a way to mark clusters as bad in Norton Utilities? I didn't see it under DiskEdit
I modified some of my Carmen Sandiego scripts to handle its files, so now I can see what chunks are where:
https://gist.github.com/foone/a8e2455dd0c5456e513cf69c56b727c8
the file DAT3 has chunks named SODOMA and SODOMB
Come on guys, just 23 more and you'll be onto something!
there's some kind of compression going on here that's inexplicably bad?
NIV & Revised Standard say "You shall not steal."
Living Bible says "You must not steal."
Only the KJV says "Thou shalt not steal."
Come on guys, you could have made it switch between the different versions of the bible based on the current setting of which version to use!
I'm gonna have to hack that in, aren't I?
The funny thing is: They're inconsistent with the fact it says "Thou shalt not steal".
Why? Because this game has FOUR BIBLES in it. Only one of those is the King James Version.
That one is a joke, but the credits do actually have an anti-piracy message followed by Exodus 20:15: Thou Shalt Not Steal
a fun part of naming functions that you don't understand yet is that it makes it look like the program was written by a really terrible programmer with a special weakness for function naming.
calculate_some_things()
code that indicates you're on 16-bit segmented x86 or you're about to break your program:
*(uint *)0x0 = uVar2;
SOME PROGRAMMERS NEED TO BE STOPPED
alloc16((((DAT_1000_c79a + 0xfU >> 1 | (uint)((DAT_1000_c79c & 1) != 0) << 0xf) >> 1 |
(uint)((DAT_1000_c79c >> 1 & 1) != 0) << 0xf) >> 1 |
(uint)((DAT_1000_c79c >> 2 & 1) != 0) << 0xf) >> 1 |
(uint)((DAT_1000_c79c >> 3 & 1) != 0) << 0xf);
it checks each DAT file it opens to see if it starts with MZ.
I guess it can accidentally open EXE files or something?
eww, this file format doesn't store the width, it stores the stride.
So it's (320,200) for an EGA 640x200 image, since it's 4 bits per pixel.
the game is running at 640x350 resolution, an EGA format.
POP QUIZ: why did they split the opening image into two separate chunks in the data file?
COULD YOU BE MORE SPECIFIC PLZ
I found the decompression routine and I hate it. it's big and complicated and there's calls to subfunctions.
reimplementing this will be a nightmare
step 1:
fill a table of 256 words with 0xFFFF
<dasharezone>OH SHIT IS THAT A MOTHERFUCKING HUFFMAN TABLE?</dasharezone>
GNU social JP is a social network, courtesy of GNU social JP管理人. It runs on GNU social, version 2.0.2-dev, available under the GNU Affero General Public License.
All GNU social JP content and data are available under the Creative Commons Attribution 3.0 license.