krisives / d2s-format

Diablo II Save File Format (.d2s format)
121 stars 19 forks source link

[Suggestion]: My C++ version of the checksum algorithm should it help anyone #13

Open hashborgir opened 2 years ago

hashborgir commented 2 years ago

This is ready to be built in VS2022.

#define _CRT_SECURE_NO_DEPRECATE

#include <iostream>
#include <stdio.h>
#include<string>

using namespace std;

char** argv = NULL;

void main(int argc, char** argv)
{
    if (argv[1] == NULL) {
        cout << "\n\n\tNo .d2s file specified. \n\n\tUsage: d2scs.exe char.d2s\n\n" << endl;
        return;
    }

    FILE* charFile;
    charFile = fopen(argv[1], "r+b");

    // zero out the previous checksum
    char zero[4] = { 0 };
    fseek(charFile, 12, SEEK_SET);
    fwrite(zero, sizeof(char),sizeof(zero), charFile);
    fflush(charFile);
    fseek(charFile, 0, SEEK_SET);

    unsigned char saveFileData[16];
    unsigned long counter = 0;
    unsigned int uSum = 0;

    int n;
    int uVar = 0;
    int byte;

    while ((n = fread(saveFileData, sizeof(char), 16, charFile)) > 0) {
        int i;
        for (i = 0; i < n; i++) {
            // Current byte in charFile     
            byte = (unsigned)saveFileData[i];

            //SAME as uSum  line, just to double check if both produce the same checksum
            if (uVar < 0)
                byte++;
            uVar = byte + uVar * 2;

            //SAME as above block, just to double check if both produce the same checksum
            uSum = ((uSum << 1) | (uSum >> 31)) + (unsigned)saveFileData[i];
        }
        counter += 16;
    }

    unsigned long r_uVar = _byteswap_ulong(uVar);
    unsigned long r_uSum = _byteswap_ulong(uSum);

    // write new checksum
    fseek(charFile, 12, SEEK_SET);
    fwrite(&uVar, sizeof(uVar), 1, charFile);
    fflush(charFile);
    fseek(charFile, 0, SEEK_SET);

    printf("\n\n\t%08x checksum written to %s\n\n", r_uVar, argv[1]);

    fclose(charFile);
}
hashborgir commented 2 years ago

Here's the original function located at 6FD269D3 inside D2Game.dll 1.10F

**************************************************************
*                                                            *
*  FUNCTION                                                  *
**************************************************************
uint __fastcall FUN_6fd269d3(byte * param_1, int param_2)
uint              EAX:4          <RETURN>
byte *            ECX:4          param_1
int               EDX:4          param_2
FUN_6fd269d3                                    XREF[1]:     FUN_6fc8a140:6fc8a187(c)  
6fd269d3 85 d2           TEST       param_2,param_2
6fd269d5 75 1b           JNZ        LAB_6fd269f2
6fd269e3 e8 06 5d        CALL       FOG.DLL::Ordinal_10023                           undefined Ordinal_10023()
ff ff
6fd269ed e8 fb 5d        CALL       FUN_6fd1c7ed                                     undefined FUN_6fd1c7ed(UINT para
ff ff
-- Flow Override: CALL_RETURN (CALL_TERMINATOR)
6fd269f3 83 c8 ff        OR         EAX,0xffffffff
LAB_6fd269f7                                    XREF[1]:     6fd26a0d(j)  
6fd269f7 0f b6 31        MOVZX      ESI,byte ptr [param_1]
6fd269fa 0f b6 f8        MOVZX      EDI,AL
6fd269fd 33 f7           XOR        ESI,EDI
6fd269ff c1 e8 08        SHR        EAX,0x8
6fd26a02 8b 34 b5        MOV        ESI,dword ptr [ESI*0x4 + DAT_6fd2a248]
48 a2 d2 6f
6fd26a09 33 c6           XOR        EAX,ESI
6fd26a0b 41              INC        param_1
6fd26a0c 4a              DEC        param_2
6fd26a0d 75 e8           JNZ        LAB_6fd269f7
6fd26a11 f7 d0           NOT        EAX
6fd26a13 c3              RET
hashborgir commented 2 years ago

Here is the original function in C++


uint __fastcall FUN_6fd269d3(byte *param_1,int param_2)

{
  uint uVar1;

  if (param_2 == 0) {
    Ordinal_10023(s__dwSize_6fd43f6b + 1,s_C:\projects\D2\head\Diablo2\Sour_6fd43f74,0x40);
                    /* WARNING: Subroutine does not return */
    FUN_6fd1c7ed(0xffffffff);
  }
  uVar1 = 0xffffffff;
  do {
    uVar1 = uVar1 >> 8 ^ *(uint *)(&DAT_6fd2a248 + ((uint)*param_1 ^ uVar1 & 0xff) * 4);
    param_1 = param_1 + 1;
    param_2 = param_2 + -1;
  } while (param_2 != 0);
  return ~uVar1;
}

If you notice there is a certain table whose values are being XOR'd with the checksum. Find the table at 6FD2A248. It's DWORD[256]

DAT_6fd2a248    XREF[1]:     FUN_6fd269d3:6fd26a02(R)  

The values in the table are as follows:

00 => 0X0
01 => 0X77073096
02 => 0XEE0E612C
03 => 0X990951BA
04 => 0X076DC419
05 => 0X706AF48F
06 => 0XE963A535
07 => 0X9E6495A3
08 => 0X0EDB8832
09 => 0X79DCB8A4
0A => 0XE0D5E91E
0B => 0X97D2D988
0C => 0X09B64C2B
0D => 0X7EB17CBD
0E => 0XE7B82D07
0F => 0X90BF1D91
10 => 0X1DB71064
11 => 0X6AB020F2
12 => 0XF3B97148
13 => 0X84BE41DE
14 => 0X1ADAD47D
15 => 0X6DDDE4EB
16 => 0XF4D4B551
17 => 0X83D385C7
18 => 0X136C9856
19 => 0X646BA8C0
1A => 0XFD62F97A
1B => 0X8A65C9EC
1C => 0X14015C4F
1D => 0X63066CD9
1E => 0XFA0F3D63
1F => 0X8D080DF5
20 => 0X3B6E20C8
21 => 0X4C69105E
22 => 0XD56041E4
23 => 0XA2677172
24 => 0X3C03E4D1
25 => 0X4B04D447
26 => 0XD20D85FD
27 => 0XA50AB56B
28 => 0X35B5A8FA
29 => 0X42B2986C
2A => 0XDBBBC9D6
2B => 0XACBCF940
2C => 0X32D86CE3
2D => 0X45DF5C75
2E => 0XDCD60DCF
2F => 0XABD13D59
30 => 0X26D930AC
31 => 0X51DE003A
32 => 0XC8D75180
33 => 0XBFD06116
34 => 0X21B4F4B5
35 => 0X56B3C423
36 => 0XCFBA9599
37 => 0XB8BDA50F
38 => 0X2802B89E
39 => 0X5F058808
3A => 0XC60CD9B2
3B => 0XB10BE924
3C => 0X2F6F7C87
3D => 0X58684C11
3E => 0XC1611DAB
3F => 0XB6662D3D
40 => 0X76DC4190
41 => 0X01DB7106
42 => 0X98D220BC
43 => 0XEFD5102A
44 => 0X71B18589
45 => 0X06B6B51F
46 => 0X9FBFE4A5
47 => 0XE8B8D433
48 => 0X7807C9A2
49 => 0X0F00F934
4A => 0X9609A88E
4B => 0XE10E9818
4C => 0X7F6A0DBB
4D => 0X086D3D2D
4E => 0X91646C97
4F => 0XE6635C01
50 => 0X6B6B51F4
51 => 0X1C6C6162
52 => 0X856530D8
53 => 0XF262004E
54 => 0X6C0695ED
55 => 0X1B01A57B
56 => 0X8208F4C1
57 => 0XF50FC457
58 => 0X65B0D9C6
59 => 0X12B7E950
5A => 0X8BBEB8EA
5B => 0XFCB9887C
5C => 0X62DD1DDF
5D => 0X15DA2D49
5E => 0X8CD37CF3
5F => 0XFBD44C65
60 => 0X4DB26158
61 => 0X3AB551CE
62 => 0XA3BC0074
63 => 0XD4BB30E2
64 => 0X4ADFA541
65 => 0X3DD895D7
66 => 0XA4D1C46D
67 => 0XD3D6F4FB
68 => 0X4369E96A
69 => 0X346ED9FC
6A => 0XAD678846
6B => 0XDA60B8D0
6C => 0X44042D73
6D => 0X33031DE5
6E => 0XAA0A4C5F
6F => 0XDD0D7CC9
70 => 0X5005713C
71 => 0X270241AA
72 => 0XBE0B1010
73 => 0XC90C2086
74 => 0X5768B525
75 => 0X206F85B3
76 => 0XB966D409
77 => 0XCE61E49F
78 => 0X5EDEF90E
79 => 0X29D9C998
7A => 0XB0D09822
7B => 0XC7D7A8B4
7C => 0X59B33D17
7D => 0X2EB40D81
7E => 0XB7BD5C3B
7F => 0XC0BA6CAD
80 => 0XEDB88320
81 => 0X9ABFB3B6
82 => 0X03B6E20C
83 => 0X74B1D29A
84 => 0XEAD54739
85 => 0X9DD277AF
86 => 0X04DB2615
87 => 0X73DC1683
88 => 0XE3630B12
89 => 0X94643B84
8A => 0X0D6D6A3E
8B => 0X7A6A5AA8
8C => 0XE40ECF0B
8D => 0X9309FF9D
8E => 0X0A00AE27
8F => 0X7D079EB1
90 => 0XF00F9344
91 => 0X8708A3D2
92 => 0X1E01F268
93 => 0X6906C2FE
94 => 0XF762575D
95 => 0X806567CB
96 => 0X196C3671
97 => 0X6E6B06E7
98 => 0XFED41B76
99 => 0X89D32BE0
9A => 0X10DA7A5A
9B => 0X67DD4ACC
9C => 0XF9B9DF6F
9D => 0X8EBEEFF9
9E => 0X17B7BE43
9F => 0X60B08ED5
A0 => 0XD6D6A3E8
A1 => 0XA1D1937E
A2 => 0X38D8C2C4
A3 => 0X4FDFF252
A4 => 0XD1BB67F1
A5 => 0XA6BC5767
A6 => 0X3FB506DD
A7 => 0X48B2364B
A8 => 0XD80D2BDA
A9 => 0XAF0A1B4C
AA => 0X36034AF6
AB => 0X41047A60
AC => 0XDF60EFC3
AD => 0XA867DF55
AE => 0X316E8EEF
AF => 0X4669BE79
B0 => 0XCB61B38C
B1 => 0XBC66831A
B2 => 0X256FD2A0
B3 => 0X5268E236
B4 => 0XCC0C7795
B5 => 0XBB0B4703
B6 => 0X220216B9
B7 => 0X5505262F
B8 => 0XC5BA3BBE
B9 => 0XB2BD0B28
BA => 0X2BB45A92
BB => 0X5CB36A04
BC => 0XC2D7FFA7
BD => 0XB5D0CF31
BE => 0X2CD99E8B
BF => 0X5BDEAE1D
C0 => 0X9B64C2B0
C1 => 0XEC63F226
C2 => 0X756AA39C
C3 => 0X026D930A
C4 => 0X9C0906A9
C5 => 0XEB0E363F
C6 => 0X72076785
C7 => 0X05005713
C8 => 0X95BF4A82
C9 => 0XE2B87A14
CA => 0X7BB12BAE
CB => 0X0CB61B38
CC => 0X92D28E9B
CD => 0XE5D5BE0D
CE => 0X7CDCEFB7
CF => 0X0BDBDF21
D0 => 0X86D3D2D4
D1 => 0XF1D4E242
D2 => 0X68DDB3F8
D3 => 0X1FDA836E
D4 => 0X81BE16CD
D5 => 0XF6B9265B
D6 => 0X6FB077E1
D7 => 0X18B74777
D8 => 0X88085AE6
D9 => 0XFF0F6A70
DA => 0X66063BCA
DB => 0X11010B5C
DC => 0X8F659EFF
DD => 0XF862AE69
DE => 0X616BFFD3
DF => 0X166CCF45
E0 => 0XA00AE278
E1 => 0XD70DD2EE
E2 => 0X4E048354
E3 => 0X3903B3C2
E4 => 0XA7672661
E5 => 0XD06016F7
E6 => 0X4969474D
E7 => 0X3E6E77DB
E8 => 0XAED16A4A
E9 => 0XD9D65ADC
EA => 0X40DF0B66
EB => 0X37D83BF0
EC => 0XA9BCAE53
ED => 0XDEBB9EC5
EE => 0X47B2CF7F
EF => 0X30B5FFE9
F0 => 0XBDBDF21C
F1 => 0XCABAC28A
F2 => 0X53B39330
F3 => 0X24B4A3A6
F4 => 0XBAD03605
F5 => 0XCDD70693
F6 => 0X54DE5729
F7 => 0X23D967BF
F8 => 0XB3667A2E
F9 => 0XC4614AB8
FA => 0X5D681B02
FB => 0X2A6F2B94
FC => 0XB40BBE37
FD => 0XC30C8EA1
FE => 0X5A05DF1B
FF => 0X2D02EF8D
hashborgir commented 2 years ago

You can either use the XOR Table and XOR the value of every byte or you can use the algorithm in the previous post.

uVar1 = uVar1 >> 8 ^ DWORD_ARRAY_6fd2a248[(uint)*param_1 ^ uVar1 & 0xff];