I'm working on this pseudocode trying to find the correct input for the expected calculated value (i'm not sure if i can call it a checksum). I can't focus enough to generate the reverse algorithm, then any kind of help is appreciated.
I may start with the value 2602618273338008543 in v20 and xor back on the random generated input but i think the end result would be too big to be xored to zero with a single byte.
PS: I commented some lines that i suppose have no effect on the computation.
A side question, why is the result checked against 2 values (loword(v20)==-922952045 && HIDWORD(v20) == -902699940 || v20 == 2602618273338008543i64) ? would the result be different when calculated in double words than with hiword/loword(dword)?
Thank you.
v20 = 0i64;
// salt table
v28="a#+EJK45fe/efJWDSlesfGe03saHHFddfdq2gr%a3ß0jm2ÜcFEF!JKMÄrAfim+wqe=WD=?f3jDKefDJ§W?)JöSeAEFj_LIeJDF"; // salt table
input = new byte[32] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
for ( j = 0; j < 200; ++j )
{
v24 = (v20 + j) % 60 + 1; // 0x3c
v15 = input[7 * j % 15];
if ( v24 == 32 ) // 0x20
v15 = __PAIR__(v15, HIDWORD(v15));
if ( v24 == 31 ) // 0x1f
{
// v22 = v24 & 31; // 0x1f
// v11 = HIDWORD(v15);
// v8 = v15;
v1 = (unsigned __int64)(v15 << (v24 & 0x1F)) >> 32;
LODWORD(v15) = __PAIR__((unsigned int)v15, HIDWORD(v15)) << (v24 & 0x1F) >> 32;
HIDWORD(v15) = v1;
}
// v6 = v15;
v20 += v15;
v25 = (v20 ^ (unsigned __int64)j) % 62 + 2; // 0x3e + 2
v2 = (v20 - j) % 91; // 0x5Bui64
LODWORD(v16) = *(int *)((char *)&v28 + v2);
HIDWORD(v16) = *(int *)((char *)&v29 + v2); // &v29=&v28-4
if ( v25 & 32 ) // 0x20
v16 = __PAIR__(v16, HIDWORD(v16));
if ( v25 & 31 ) // 0x1f
{
// v21 = v25 & 31; // 0x1f
// v9 = HIDWORD(v16);
// v10 = v16;
v3 = (unsigned __int64)(v16 << (v25 & 0x1F)) >> 32;
LODWORD(v16) = __PAIR__((unsigned int)v16, HIDWORD(v16)) << (v25 & 0x1F) >> 32;
HIDWORD(v16) = v3;
}
v7 = v16;
v20 ^= v16;
}
if ( (_DWORD)v20 == -922952045 && HIDWORD(v20) == -902699940 || v20 == 2602618273338008543i64 )
v23 = 1;
}
Edit:
Here is a valid C++ code for the same algorithm.
#define LODWORD(_qw) ((DWORD)(_qw))
#define HIDWORD(_qw) ((DWORD)(((_qw) >> 32) & 0xffffffff))
uint64_t v22, v11, v6, v7, v9, v21, v20, v24, v15, v16, v25, v2, v3, vx = 0;
const char _v28[] = "a#+EJK45fe/efJWDSlesfGe03saHHFddfdq2gr%a3ß0jm2ÜcFEF!JKMÄrAfim+wqe=WD=?f3jDKefDJ§W?)JöSeAEFj_LIeJDF"; // salt table
const byte input[] = { 0x3B, 0x8F, 0x80, 0x01, 0x00, 0x00, 0x53, 0x54, 0x4F, 0x4C, 0x4C, 0x4D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A };
int j, v1, v8, v10;
uint64_t QW_Swap(uint64_t v)
{
uint64_t temp = v & 0xFFFFFFFF; // extract the low
v >>= 32; // shift right
v |= (temp << 32); // put the previous low in the high
return v;
}
void setLODWORD(uint64_t *_var, DWORD _v)
{
*_var &= 0xFFFFFFFF00000000;
*_var |= (uint64_t)_v;
}
void setHIDWORD(uint64_t *_var, DWORD _v)
{
*_var &= 0xFFFFFFFF;
*_var |= (uint64_t)_v << 32;
}
void atrCRC()
{
v20 = 0;
v16 = 0;
byte * inp;
inp = (byte*)&input;
byte * v28;
v28 = (byte*)&_v28;
for (j = 0; j < 200; ++j)
{
v24 = (v20 + j) % 0x3C + 1;
v15 = *(uint64_t*)(inp+(7 * j % 15));
if (v24 & 0x20)
v15 = QW_Swap(v15);
if (v24 & 0x1F)
{
v22 = v24 & 0x1F;
v11 = HIDWORD(v15);
v8 = v15;
v1 = (uint64_t)(v15 << (v24 & 0x1F)) >> 32;
setLODWORD(&v15, (QW_Swap(v15) << (v24 & 0x1F) >> 32));
setHIDWORD(&v15, v1);
}
v6 = v15;
v20 += v15;
v25 = (v20 ^ (uint64_t)j) % 0x3E + 2;
v2 = (v20 - j) % 0x5B;
setLODWORD(&v16, *(int *)((char *)(v28 + v2)));
setHIDWORD(&v16, *(int *)((char *)((v28 + v2) +4)));
if (v25 & 0x20)
v16 = QW_Swap(v16);
if (v25 & 0x1F)
{
v21 = v25 & 0x1F;
v9 = HIDWORD(v16);
v10 = v16;
v3 = (uint64_t)(v16 << (v25 & 0x1F)) >> 32;
setLODWORD(&v16, (QW_Swap(v16) << (v25 & 0x1F) >> 32));
setHIDWORD(&v16, v3);
}
v7 = v16;
v20 ^= v16;
}
/*
if (v20 == -922952045 && HIDWORD(v20) == -902699940 || v20 == 2602618273338008543i64)
v23 = 1;
*/
}
EDIT 2: a bit simplified code
#define LODWORD(_qw) ((DWORD)(_qw))
#define HIDWORD(_qw) ((DWORD)(((_qw) >> 32) & 0xffffffff))
uint64_t v22, v20, v24, v15, v2, v3 = 0;
const char _v28[] = "a#+EJK45fe/efJWDSlesfGe03saHHFddfdq2gr%a3ß0jm2ÜcFEF!JKMÄrAfim+wqe=WD=?f3jDKefDJ§W?)JöSeAEFj_LIeJDF"; // salt table
const byte input[] = { 0x3B, 0x8F, 0x80, 0x01, 0x00, 0x00, 0x53, 0x54, 0x4F, 0x4C, 0x4C, 0x4D, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3A };
int j;
uint64_t QW_Swap(uint64_t v)
{
uint64_t temp = v & 0xFFFFFFFF; // extract the low
v >>= 32; // shift right
v |= (temp << 32); // put the previous low in the high
return v;
}
void setLODWORD(uint64_t *_var, DWORD _v)
{
*_var &= 0xFFFFFFFF00000000;
*_var |= (uint64_t)_v;
}
void setHIDWORD(uint64_t *_var, DWORD _v)
{
*_var &= 0xFFFFFFFF;
*_var |= (uint64_t)_v << 32;
}
void func(uint64_t x, uint64_t *var)
{
byte v22;
int t;
if (x & 0x20)
*var = QW_Swap(*var);
if (x & 0x1F)
{
v22 = x & 0x1F;
t = (uint64_t)(*var << v22) >> 32;
setLODWORD(var, (QW_Swap(*var) << v22 >> 32));
setHIDWORD(var, t);
}
}
void atrCRC()
{
v20 = 0;
byte * inp;
inp = (byte*)&input;
byte * v28;
v28 = (byte*)&_v28;
for (j = 0; j < 200; ++j)
{
v24 = (v20 + j) % 0x3C + 1; // v20 = ((v24-1)*0x3c)-j;
v15 = *(uint64_t*)(inp+(7 * j % 15)); // *(uint64_t*)(out[j*15%7]) = v15;
func(v24, &v15);
v20 += v15;
v24 = (v20 ^ (uint64_t)j) % 0x3E + 2;
v2 = (v20 - j) % 0x5B;
setLODWORD(&v15, *(int *)((char *)(v28 + v2)));
setHIDWORD(&v15, *(int *)((char *)((v28 + v2) +4)));
func(v24, &v15);
v20 ^= v15;
}
}