can-you-crack-this
The main function reads the input and constrains the length.
v11 = std::operator<<<std::char_traits<char>>(&std::cout, "Enter your public key: ");
std::ostream::operator<<(v11, std::endl<char,std::char_traits<char>>);
std::operator>><char>(&std::cin, public_key);
if ( (unsigned __int64)std::string::length(public_key) >= 20 ) {
v9 = std::operator<<<std::char_traits<char>>(&std::cout, "Enter serial key:");
std::ostream::operator<<(v9, std::endl<char,std::char_traits<char>>);
std::operator>><char>(&std::cin, serial_key);
v8 = 4 * std::string::length(public_key) - 1;
if ( v8 == std::string::length(serial_key) ) {
std::string::basic_string(str_public_key, public_key);
std::string::basic_string(str_serial_key, serial_key);
v6 = verify_serial((__int64)str_public_key, (__int64)str_serial_key);
std::string::~string(str_serial_key);
std::string::~string(str_public_key);
if ( v6 ) {
v5 = std::operator<<<std::char_traits<char>>(&std::cout, "Serial accepted.");
std::ostream::operator<<(v5, std::endl<char,std::char_traits<char>>);
}
else {
v4 = std::operator<<<std::char_traits<char>>(&std::cout, "Try harder.");
std::ostream::operator<<(v4, std::endl<char,std::char_traits<char>>);
}
v17 = 0;
v14 = 1;
}
else {
v7 = std::operator<<<std::char_traits<char>>(&std::cout, "Invalid serial length.");
std::ostream::operator<<(v7, std::endl<char,std::char_traits<char>>);
v17 = 0;
v14 = 1;
}
}
else {
v10 = std::operator<<<std::char_traits<char>>(&std::cout, "Invalid length.");
std::ostream::operator<<(v10, std::endl<char,std::char_traits<char>>);
v17 = 0;
v14 = 1;
}
It requires that the two input strings satisfy the constraint len(serial) = len(publik_key) * 4 - 1
and passes the two strings into the verify_serial()
function.
_BOOL8 __fastcall verify_serial(__int64 a1, __int64 a2) {
__int64 v2; // rsi
__int64 v3; // rax
const char *v4; // rax
__int64 v6; // [rsp+10h] [rbp-C0h]
bool v7; // [rsp+1Bh] [rbp-B5h]
char *char_from_pb_key; // [rsp+20h] [rbp-B0h]
char v10[24]; // [rsp+38h] [rbp-98h] BYREF
char sub_serial[28]; // [rsp+50h] [rbp-80h] BYREF
int v12; // [rsp+6Ch] [rbp-64h]
__int64 count; // [rsp+70h] [rbp-60h]
char sub_serial_v12[24]; // [rsp+88h] [rbp-48h] BYREF
__int64 pos_v13; // [rsp+A0h] [rbp-30h]
__int64 v16; // [rsp+A8h] [rbp-28h]
char v17[28]; // [rsp+B0h] [rbp-20h] BYREF
_BOOL4 v18; // [rsp+CCh] [rbp-4h]
std::string::basic_string<std::nullptr_t>(v17, "-");
v16 = 0LL;
pos_v13 = 0LL;
std::string::basic_string((__int64)sub_serial_v12);
count = 0LL;
while ( 1 ) {
pos_v13 = std::string::find(a2, v17, 0LL);
if ( pos_v13 == -1 )
break;
++count;
if ( pos_v13 != 3 ) {
v18 = 0;
v12 = 1;
goto L_EXIT;
}
std::string::substr(sub_serial, a2, 0LL, 3LL);
std::string::operator=((__int64)sub_serial_v12, (__int64)sub_serial);
std::string::~string(sub_serial);
std::string::basic_string(v10, sub_serial_v12);
v2 = v16++;
char_from_pb_key = (char *)std::string::at(a1, v2);
v7 = !verify_char(v10, *char_from_pb_key);
std::string::~string(v10);
if ( v7 ) {
v18 = 0;
v12 = 1;
goto L_EXIT;
}
v6 = pos_v13;
v3 = std::string::length(v17);
std::string::erase(a2, 0LL, v3 + v6);
}
if ( count == 19 ) {
v4 = (const char *)std::string::c_str(a2);
v18 = strncmp(v4, "bss", 3uLL) == 0;
}
else {
v18 = 0;
}
v12 = 1;
L_EXIT:
std::string::~string(sub_serial_v12);
std::string::~string(v17);
return v18;
}
This function splits the Serial Key into 20 parts by -
and requires each part to be 3 in length, ending with bss
.
The three characters of each Serial Key part and one Public Key character in the corresponding position are passed to the verify_char()
function.
_BOOL8 __fastcall verify_char(char *a1, char a2) {
const char *v2; // rax
int v3; // eax
unsigned __int64 v5; // [rsp+0h] [rbp-20h]
__int64 v6; // [rsp+8h] [rbp-18h]
__int64 v7; // [rsp+10h] [rbp-10h]
v2 = (const char *)std::string::c_str(a1);
v7 = strtol(v2, 0LL, 16);
v6 = fib(v7); // fib / 100
v5 = v6;
do {
do
--v5;
while ( !check_arm(v5) );
} while ( (unsigned int)notused(v5) || v5 > 0x10E47F4C575565LL );
if ( v7 >= 100 ) {
if ( (unsigned int)isprint(a2) ) {
v3 = UN++;
used[v3] = v5;
return v5 && v6 && v5 != v6 && (v6 - v5) % 100 == a2;
}
}
return 0;
}
This function first converts the hex string (format of input) to int, then uses fib()
to calculate the value of that index in the Fibonacci series and divides it by 100 to return v6
.
The check_arm()
function is as follows
_BOOL8 __fastcall check_arm(__int64 a1) {
return (countSetBits(a1) & 1) == 1;
}
__int64 __fastcall countSetBits(__int64 a1) {
unsigned int v2; // [rsp+0h] [rbp-Ch]
v2 = 0;
while ( a1 ) {
a1 &= a1 - 1;
++v2;
}
return v2;
}
countSetBits()
is used to calculate the number of 1 in the binary form of the argument, so the number of 1 is odd to exit the inner do while
loop. For the outer loop, the number v5
must be less than 0x10E47F4C575565, and notused()
will record the previous v5
and cannot be reused.
In addition, since v6 - v5 > 0x20
(isprint(a2)
and (v6 - v5) % 100 == a2
) is required, it is obvious that the upper limit of v5
needs to be used in the construction. So that the value of v5
in 20 calculations can be determined, and the Serial Key and Public Key can be constructed by finding (v6, a2)
that match the condition.
#include <stdio.h>
unsigned long long fib(unsigned long long x) {
long long v5[4096];
v5[0] = 0;
v5[1] = 1;
for (int i = 2; i <= x; i++)
v5[i] = v5[i - 1] + v5[i - 2];
return v5[x] / 100uLL;
}
long long countSetBits(long long x) {
unsigned int v2 = 0;
while (x) {
x &= x - 1;
v2++;
}
return v2;
}
int check_arm(unsigned long long x) {
return (countSetBits(x) & 1) == 1;
}
void next(long long *v5) {
do {
--*v5;
} while (!check_arm(*v5));
return;
}
int main() {
unsigned long long v7;
long long v5 = 0x10E47F4C575565LL;
int serial[105];
int public[105];
for (int i = 0; i < 20; i++){
next(&v5);
for (int j = 100; j < 0x1000; j++){
long long tmp = (fib(j) - v5) % 100;
// add constraints of fib(j) > 0x10E47F4C575565LL is better
if (tmp > 0x20){
serial[i] = j;
public[i] = tmp;
break;
}
}
}
printf("Public Key: ");
for (int i = 0; i < 20; i++)
printf("%c", public[i]);
printf("\n");
printf("Serial Key: ");
for (int i = 0; i < 19; i++)
printf("%03x-", serial[i]);
printf("bss\n");
return 0;
}
// Public Key: ;=>ABDGH#%&(+-.12479
// Serial Key: 066-066-066-066-066-066-066-066-064-064-064-064-064-064-064-064-064-064-064-bss