Reversing a simple hex calculation

Hello

I have a microcontroller running a program, of which I don't have the source code. This program writes a value in an EEPROM chip. This value (let's say it ranges between 0 and 10000) is first "encrypted", then stored as 2 bytes.


For example, if the value before "encryption" is 1000, which is 0x03E8, it will be encrypted and stored in EEPROM as 0x03EB

What I found to always "decrypt" the value, simply substract the most significant byte : 0x03EB - 0x03 = 0x03E8.

So if I want to encrypt value 1000, I do the reverse, obviously I ADD the most significant byte : 0x03E8 + 0x03 = 0x03EB . It works in this case.


If I take another value, for example 7160 which is 0x1BF8. I know that the program will encrypt this value as 0x1C14, and again substracting the MSB : 0x1C14 - 0x1C = 0x1BF8.

But this time, if I want to reverse it, of course adding the Most significant byte is wrong : 0x1BF8 + 0x1B = 0x1C13, which is not the expected 0x1C14 as when encrypted by the program.


So how to properly "encrypt" any value and get the expected result ?

Thanks

There are many possible encryption algorithms and simple addition/subtraction is clearly not being used in this case. More likely, exclusive OR is used in some sequence of operations, with some key.

If you collect a number of known valid encryption examples, it is often possible to guess or deduce the pattern.

@guix I think you mixed up the cases. For value 0x1bf8 , the answer

will be correcr and not the 0x1c14

No, I expect 0x1BF8 to be encrypted as 0x1C14, as that is what the program outputs. I am trying to replicate what is done by the program, it looks simple but I can't find what it is doing exactly :slight_smile:

Please post some other examples of what the program outputs. Very useful information would result if the inputs differ by only a single bit, so I suggest to input 0, 1, 2, 4, 8 up to 0x8000 and post the results.

@guix

game developers protecting important values against cheater by storing modified value and if game see stored unmodified value it know that cheat is activated and reset game or something. modification is something like: Enc= value * 1.0039106;

@kolaha I tested with input value 0x2BF8 and it is encoded and stored as 0x2C24. And again 0x2C24 - 0x2C = 0x2BF8

@jremington I will do more tests and report

Thanks

multiplication by 1.0039 still works

round(0x2bf8 * 1.0039) = 0x2C24;
round(0x2C24 / 1.0039) = 0x2BF8;

round(0x1BF8 * 1.0039) = 0x1C14;
round(0x1C14 / 1.0039) = 0x1BF8;

Interesting

Possibly adding the MSB to the number, plus 1 if there is a carry produced when adding the MSB to the LSB.

1 Like

Some examples of output, for input values < decimal 256 might be informative.

Multiplying by 1.0039 or by (1 + 1/256) is basically the same thing as adding the MSB to the LSB, with the possibility of adding the carry, suggested by @david_2018.

1 Like
Enc = X + (X >> 8) + ((((X + (X >> 8)) >> 8) != (X >> 8)) ? 1 : 0);
and
X = Enc - (Enc >> 8);

or

byte HB = X>>8;
byte n = (X + (X >> 8)) >> 8;
Enc = X + HB  + (HB  != n ? 1 : 0);

or

byte HB = X & 0xFF00;
int LB = (X & 0xFF) + (X >> 8) ;
Enc = (LB | HB) + (LB >= 0x100 ? 1 : 0);

or

int SB = (X + (X >> 8)) >> 8;
Enc = X + SB;
1 Like

That is straight 16 bit hex number. The Arduino and most others use that, not decimal so it is not encrypted. You can use an online hex calculator or possibly your pocket calculator to decoe. If you tell the Arduino to simply print it it will make it decimal.

Thanks, that is clever and I tried with a lot of input values, it works perfect :slight_smile:

Thanks all