Skip to content

Instantly share code, notes, and snippets.

@adenkiewicz
Created July 9, 2019 09:23
Show Gist options
  • Save adenkiewicz/f031946a0109f37b673a837165995e40 to your computer and use it in GitHub Desktop.
Save adenkiewicz/f031946a0109f37b673a837165995e40 to your computer and use it in GitHub Desktop.
PoC implementation of Alternate Data Stream browser.
#include <iostream>
#include <locale>
#include <codecvt>
#include <string>
#include <Windows.h>
#include <WinBase.h>
#include <io.h>
#include <fcntl.h>
void getADS_find(const std::wstring& filename) {
WIN32_FIND_STREAM_DATA fileData, streamData;
constexpr DWORD reserved = 0;
HANDLE file = FindFirstStreamW(filename.c_str(), FindStreamInfoStandard, &fileData, reserved);
if (file == INVALID_HANDLE_VALUE)
return;
while (FindNextStreamW(file, &streamData)) {
std::wcout << L"\t" << streamData.cStreamName << L"\t(size: " << streamData.StreamSize.QuadPart << L")" << std::endl;
}
}
namespace {
constexpr auto ALTERNATE_DATA_STREAM = 0x4;
}
void getADS_backup(const std::wstring& filename) {
HANDLE file = CreateFileW(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (file == INVALID_HANDLE_VALUE)
return;
DWORD bytesRead = 0;
LPVOID ptr = nullptr;
WIN32_STREAM_ID streamInfo;
WCHAR streamName[MAX_PATH + 1];
while (BackupRead(file, (LPBYTE)&streamInfo, sizeof(WIN32_STREAM_ID) - 4, &bytesRead, FALSE, FALSE, &ptr)) {
if (streamInfo.dwStreamId == ALTERNATE_DATA_STREAM) {
memset(streamName, NULL, sizeof(streamName));
if (!BackupRead(file, (LPBYTE)streamName, streamInfo.dwStreamNameSize, &bytesRead, FALSE, TRUE, &ptr))
break;
std::wcout << L"\t" << std::wstring(streamName, bytesRead) << L"\t(size: " << streamInfo.Size.QuadPart << L")" << std::endl;
}
DWORD low, high;
if (!BackupSeek(file, streamInfo.Size.LowPart, streamInfo.Size.HighPart, &low, &high, &ptr)) {
break;
}
}
// call ABORT on backup
BackupRead(file, (LPBYTE)&streamInfo, sizeof(WIN32_STREAM_ID), &bytesRead, TRUE, TRUE, &ptr);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
std::cerr << "Usage: " << argv[0] << " <path to file>" << std::endl;
exit(-1);
}
// set console mode to handle weird UTF-16 characters
_setmode(_fileno(stdout), _O_U16TEXT);
std::wstring filename = std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(argv[1]);
std::wcout << filename << L": // using FindFirstStream, FindNextStream" << std::endl;
getADS_find(filename);
std::wcout << std::endl;
std::wcout << filename << L": // using BackupRead, BackupSeek" << std::endl;
getADS_backup(filename);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment