Skip to content

Instantly share code, notes, and snippets.

@JohnLaTwC
Created October 6, 2020 03:01
Show Gist options
  • Select an option

  • Save JohnLaTwC/0b7d3e0132f8d0247801d0c02dd8c1ec to your computer and use it in GitHub Desktop.

Select an option

Save JohnLaTwC/0b7d3e0132f8d0247801d0c02dd8c1ec to your computer and use it in GitHub Desktop.

Revisions

  1. JohnLaTwC created this gist Oct 6, 2020.
    295 changes: 295 additions & 0 deletions raccine.cpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,295 @@
    // Raccine
    // A Simple Ransomware Vaccine
    // https://github.com/Neo23x0/Raccine
    //
    // Florian Roth, Ollie Whitehouse

    #include <WCHAR.h>
    #include <windows.h>
    #include <tlhelp32.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdio.h>
    #include <chrono>
    #include <thread>
    #include <locale.h>
    #include <psapi.h>
    #include <string>
    #include <vector>

    #pragma comment(lib,"advapi32.lib")

    DWORD getppid(DWORD pid) {
    PROCESSENTRY32 pe32;
    HANDLE hSnapshot;
    DWORD ppid = 0;
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    __try {
    if (hSnapshot == INVALID_HANDLE_VALUE) __leave;
    ZeroMemory(&pe32, sizeof(pe32));
    pe32.dwSize = sizeof(pe32);
    if (!Process32First(hSnapshot, &pe32)) __leave;
    do {
    if (pe32.th32ProcessID == pid){
    ppid = pe32.th32ParentProcessID;
    break;
    }
    } while (Process32Next(hSnapshot, &pe32));
    }
    __finally {
    if (hSnapshot != INVALID_HANDLE_VALUE) CloseHandle(hSnapshot);
    }
    return ppid;
    }

    DWORD IntegrityLevel(HANDLE hProcess) {

    HANDLE hToken = INVALID_HANDLE_VALUE;
    DWORD dwIntegrityLevel = 0;
    PTOKEN_MANDATORY_LABEL pTIL;
    DWORD dwLengthNeeded = sizeof(pTIL);

    OpenProcessToken(hProcess, TOKEN_QUERY, &hToken);

    GetTokenInformation(hToken, TokenIntegrityLevel, NULL, 0, &dwLengthNeeded);
    pTIL = (PTOKEN_MANDATORY_LABEL) LocalAlloc(0, dwLengthNeeded);
    if (!pTIL) {
    return 0;
    }

    if (GetTokenInformation(hToken, TokenIntegrityLevel,
    pTIL, dwLengthNeeded, &dwLengthNeeded)) {
    dwIntegrityLevel = *GetSidSubAuthority(pTIL->Label.Sid,
    (DWORD)(UCHAR)(*GetSidSubAuthorityCount(pTIL->Label.Sid) - 1));

    LocalFree(pTIL);

    if (dwIntegrityLevel == SECURITY_MANDATORY_LOW_RID) {
    // Low Integrity
    return 1;
    }
    else if (dwIntegrityLevel >= SECURITY_MANDATORY_MEDIUM_RID &&
    dwIntegrityLevel < SECURITY_MANDATORY_HIGH_RID) {
    // Medium Integrity
    return 2;
    }
    else if (dwIntegrityLevel >= SECURITY_MANDATORY_HIGH_RID &&
    dwIntegrityLevel < SECURITY_MANDATORY_SYSTEM_RID) {
    // High Integrity
    return 3;
    }
    else if (dwIntegrityLevel >= SECURITY_MANDATORY_SYSTEM_RID) {
    // System Integrity
    return 4;
    }
    else {
    return 0;
    }
    }
    else {
    LocalFree(pTIL);
    return 0;
    }
    return 0;
    }

    BOOL isallowlisted(DWORD pid) {
    WCHAR allowlist[3][MAX_PATH] = { L"wininit.exe", L"winlogon.exe", L"explorer.exe" };
    PROCESSENTRY32 pe32 = { 0 };
    HANDLE hSnapshot;
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    __try {
    if(hSnapshot == INVALID_HANDLE_VALUE) __leave;

    ZeroMemory(&pe32, sizeof(pe32));
    pe32.dwSize = sizeof(pe32);

    if (!Process32First(hSnapshot, &pe32)) __leave;

    do {
    if (pe32.th32ProcessID == pid){
    for (uint8_t i = 0; i < ARRAYSIZE(allowlist); i++) {

    if (_wcsicmp((wchar_t*)pe32.szExeFile, allowlist[i]) == 0 ) {

    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID);

    if (hProcess != NULL) {
    wchar_t filePath[MAX_PATH] = { 0 };
    if (GetModuleFileNameEx(hProcess, NULL, filePath, MAX_PATH)) {
    DWORD dwInLevel = IntegrityLevel(hProcess);

    // Are they in the Windows directory?
    if (_wcsnicmp(filePath, L"C:\\Windows\\System32\\", wcslen(L"C:\\Windows\\System32\\")) == 0) {

    // Is the process running as SYSTEM
    if (IntegrityLevel(hProcess) == 4) {
    CloseHandle(hProcess);
    return TRUE;
    }
    }

    // Are you explorer running in the Windows dir
    if (_wcsnicmp(filePath, L"C:\\Windows\\Explorer.exe", wcslen(L"C:\\Windows\\Explorer.exe")) == 0) {

    // Is the process running as MEDIUM (which Explorer does)
    if (IntegrityLevel(hProcess) == 2) {
    CloseHandle(hProcess);
    return TRUE;
    }
    }
    }
    else {
    CloseHandle(hProcess);
    }
    }
    } // _wcsicmp
    }
    break;
    }
    } while (Process32Next(hSnapshot, &pe32));
    }
    __finally {
    if (hSnapshot != INVALID_HANDLE_VALUE) CloseHandle(hSnapshot);
    }
    return FALSE;
    }

    BOOL killprocess(DWORD dwProcessId, UINT uExitCode) {
    DWORD dwDesiredAccess = PROCESS_TERMINATE;
    BOOL bInheritHandle = FALSE;
    HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
    if (hProcess == NULL)
    return FALSE;

    BOOL result = TerminateProcess(hProcess, uExitCode);
    CloseHandle(hProcess);
    return result;
    }

    int wmain(int argc, WCHAR* argv[]) {

    DWORD pids[1024] = { 0 };
    uint8_t c = 0;
    DWORD pid = GetCurrentProcessId();

    setlocale(LC_ALL, "");

    bool bVssadmin = false;
    bool bWmic = false;
    bool bWbadmin = false;

    bool bDelete = false;
    bool bShadow = false;
    bool bResize = false;
    bool bShadowStorage = false;
    bool bShadowCopy = false;
    bool bCatalog = false;
    bool bQuiet = false;


    if (argc > 1)
    {
    // check for invoked program
    if ((_wcsicmp(L"vssadmin.exe", argv[1]) == 0) ||
    (_wcsicmp(L"vssadmin", argv[1]) == 0)) {
    bVssadmin = true;
    }
    else if ((_wcsicmp(L"wmic.exe", argv[1]) == 0) ||
    (_wcsicmp(L"wmic", argv[1]) == 0)) {
    bWmic = true;
    }
    else if ((_wcsicmp(L"wbadmin.exe", argv[1]) == 0) ||
    (_wcsicmp(L"wbadmin", argv[1]) == 0)) {
    bWbadmin = true;
    }
    }

    // check for keywords in command line parameters
    for (int iCount = 0; iCount < argc; iCount++)
    {
    if (_wcsicmp(L"delete", argv[iCount]) == 0) {
    bDelete = true;
    }
    else if (_wcsicmp(L"shadows", argv[iCount]) == 0) {
    bShadow = true;
    }
    else if (_wcsicmp(L"shadowstorage", argv[iCount]) == 0) {
    bShadowStorage = true;
    }
    else if (_wcsicmp(L"resize", argv[iCount]) == 0) {
    bResize = true;
    }
    else if (_wcsicmp(L"shadowcopy", argv[iCount]) == 0) {
    bShadowCopy = true;
    }
    else if (_wcsicmp(L"catalog", argv[iCount]) == 0) {
    bCatalog = true;
    }
    else if (_wcsicmp(L"-quiet", argv[iCount]) == 0) {
    bQuiet = true;
    }
    }

    // OK this is not want we want
    // we want to kill the process responsible
    if ((bVssadmin && bDelete && bShadow) || (bVssadmin && bResize && bShadowStorage) || // vssadmin.exe
    (bWmic && bDelete && bShadowCopy) || // wmic.exe
    (bWbadmin && bDelete && bCatalog && bQuiet)) { // wbadmin.exe

    wprintf(L"Raccine detected malicious activity\n");

    // Collect PIDs to kill
    while (true) {
    try {
    pid = getppid(pid);
    if (pid == 0) {
    break;
    }
    if (!isallowlisted(pid)) {
    wprintf(L"Collecting PID %d for a kill\n", pid);
    pids[c] = pid;
    c++;
    }
    else {
    wprintf(L"Process with PID %d is on allowlist\n", pid);
    }
    }
    catch (...) {
    wprintf(L"Couldn't kill PID %d\n", pid);
    break;
    }
    }

    // Loop over collected PIDs and try to kill the processes
    for (uint8_t i = c; i > 0; --i) {
    wprintf(L"Kill PID %d\n", pids[i - 1]);
    killprocess(pids[i - 1], 1);
    }

    wprintf(L"Raccine v0.5.0 finished\n");
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    }
    //
    // Otherwise launch it
    //
    else {
    DEBUG_EVENT debugEvent = { 0 };
    std::wstring commandLineStr = L"";

    for (int i = 1; i < argc; i++) commandLineStr.append(std::wstring(argv[i]).append(L" "));

    STARTUPINFO info = { sizeof(info) };
    PROCESS_INFORMATION processInfo;

    if (CreateProcess(NULL, (LPWSTR)commandLineStr.c_str(), NULL, NULL, TRUE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &info, &processInfo))
    {
    DebugActiveProcessStop(processInfo.dwProcessId);
    WaitForSingleObject(processInfo.hProcess, INFINITE);
    CloseHandle(processInfo.hProcess);
    CloseHandle(processInfo.hThread);
    }
    }
    return 0;
    }