I thoroughly enjoyed both your RE videos, they're easy to follow and I learned a ton. Any chance of sharing more of your wisdom in the future? I'd really like some pointers on the general approach to reverse engineering DOS-era games. I just started my own RE project, and got the first few routines RE'd with Ghidra, but it's all uphill from here. :D
Around 3:30 he mentions if you XOR an old value against a new value, you get the bits that changed.. and it's true: 00 -> 00 = 00; Masked: 0 00 -> 01 = 01; Masked: 0 00 -> 10 = 10; Masked: 1 00 -> 11 = 11; Masked: 1 01 -> 00 = 01; Masked: 0 01 -> 01 = 00; Masked: 0 01 -> 10 = 11; Masked: 1 01 -> 11 = 10; Masked: 1 10 -> 00 = 10; Masked: 1 10 -> 01 = 11; Masked: 1 10 -> 10 = 00; Masked: 0 10 -> 11 = 01; Masked: 0 11 -> 00 = 11; Masked: 1 11 -> 01 = 10; Masked: 1 11 -> 10 = 01; Masked: 0 11 -> 11 = 00; Masked: 0 In the video's example some of the bits were masked. Since it's a timer, as the number increments you could ignore the first x amount of seconds by masking off the first few bits. In my example above, if you used a bitmask of 01 and XOR that (TEST would use a bitmask of 10 instead), it'll take just the leftmost bit. It's a really efficient way of making a simple wait/timer in this case I think, although it may not be high precision depending on CPU speed and other variables. The other disadvantage is the CPU won't do anything else during the loop in this naive case. If you see any mistakes in my comment please let me know.
Great videos! I'm also looking into reverse engineering an old dos game, it's in a NE executable, but I've still found your videos very informative. Are you planning on porting this game to a modern platform? Looking forward to the next one!
Great videos. I hope you'll make some more. There have been some interesting coding practices in this game, and I see a couple of optimisations that could be made - if they really mattered for performance, but I suspect not. E.g. in this first video when checking for yes/no replies, a small optimisation that could have been made is to take the character code, OR it with 32, and then you only need to test against the lower case character, since an upper case character would then have been converted to lower case. And in this second video when creating the delay loop I don't really see the need to do much more than AND the timer value with 0x3 and see if that results in zero before continuing. It seems a bit convoluted to XOR against the previous value looking for changes in the upper bits.
Since it's a timer, just checking for ...00 could in theory miss an update, eg ...11 then ...01. I don't know how likely that is in this context where the loop seems quite short, but it's probably a habitual/copy pasted standard timer loop.
Thanks for your kind words! I made further progress in reverse engineering this game but it got a little more involved and I had a lot more work to prepare the next video, which slowed me down. I'm planning to get back to it, and it's a great source of motivation to know that people are enjoying it. I agree with both of your remarks, there are some opportunities in this game to optimize both the speed and the size of the code. There are also a few things which seem useless or redundant (like in the video mode initialization in the first video). I assume it's simply a consequence of the game having been written solo by a teenager and over a short period of time. But those small issues aren't detrimental to the functionalities of the game in any way. I secretly hope to find an actual bug in there at some point, but chances are slim. In any case, it remains really humbling to look at this code, while thinking about the circumstances of its creation. And the little mistakes add a human dimension to it.
I thoroughly enjoyed both your RE videos, they're easy to follow and I learned a ton. Any chance of sharing more of your wisdom in the future? I'd really like some pointers on the general approach to reverse engineering DOS-era games. I just started my own RE project, and got the first few routines RE'd with Ghidra, but it's all uphill from here. :D
Oh man, I really hope you continue this series. This is fantastic content.
Around 3:30 he mentions if you XOR an old value against a new value, you get the bits that changed.. and it's true:
00 -> 00 = 00; Masked: 0
00 -> 01 = 01; Masked: 0
00 -> 10 = 10; Masked: 1
00 -> 11 = 11; Masked: 1
01 -> 00 = 01; Masked: 0
01 -> 01 = 00; Masked: 0
01 -> 10 = 11; Masked: 1
01 -> 11 = 10; Masked: 1
10 -> 00 = 10; Masked: 1
10 -> 01 = 11; Masked: 1
10 -> 10 = 00; Masked: 0
10 -> 11 = 01; Masked: 0
11 -> 00 = 11; Masked: 1
11 -> 01 = 10; Masked: 1
11 -> 10 = 01; Masked: 0
11 -> 11 = 00; Masked: 0
In the video's example some of the bits were masked. Since it's a timer, as the number increments you could ignore the first x amount of seconds by masking off the first few bits. In my example above, if you used a bitmask of 01 and XOR that (TEST would use a bitmask of 10 instead), it'll take just the leftmost bit.
It's a really efficient way of making a simple wait/timer in this case I think, although it may not be high precision depending on CPU speed and other variables. The other disadvantage is the CPU won't do anything else during the loop in this naive case. If you see any mistakes in my comment please let me know.
Great videos!
I'm also looking into reverse engineering an old dos game, it's in a NE executable, but I've still found your videos very informative.
Are you planning on porting this game to a modern platform?
Looking forward to the next one!
Great videos. I hope you'll make some more.
There have been some interesting coding practices in this game, and I see a couple of optimisations that could be made - if they really mattered for performance, but I suspect not.
E.g. in this first video when checking for yes/no replies, a small optimisation that could have been made is to take the character code, OR it with 32, and then you only need to test against the lower case character, since an upper case character would then have been converted to lower case.
And in this second video when creating the delay loop I don't really see the need to do much more than AND the timer value with 0x3 and see if that results in zero before continuing. It seems a bit convoluted to XOR against the previous value looking for changes in the upper bits.
Since it's a timer, just checking for ...00 could in theory miss an update, eg ...11 then ...01. I don't know how likely that is in this context where the loop seems quite short, but it's probably a habitual/copy pasted standard timer loop.
Thanks for your kind words! I made further progress in reverse engineering this game but it got a little more involved and I had a lot more work to prepare the next video, which slowed me down. I'm planning to get back to it, and it's a great source of motivation to know that people are enjoying it.
I agree with both of your remarks, there are some opportunities in this game to optimize both the speed and the size of the code. There are also a few things which seem useless or redundant (like in the video mode initialization in the first video). I assume it's simply a consequence of the game having been written solo by a teenager and over a short period of time. But those small issues aren't detrimental to the functionalities of the game in any way. I secretly hope to find an actual bug in there at some point, but chances are slim.
In any case, it remains really humbling to look at this code, while thinking about the circumstances of its creation. And the little mistakes add a human dimension to it.
@@fabricelete5337I'm guessing you've lost motivation to work on the next episode in the series, but i'd still love to see it :3