他人の空似自作物置場

jane_style_ad_block.zip/jane_style_ad_block/main.cpp


#include <iostream>
#include <iterator>
#include <string>

#include <boost/version.hpp>
#include <boost/static_assert.hpp>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/range/irange.hpp>

#include <Windows.h>
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#include <winhttp.h>
#pragma comment(lib, "Winhttp.lib")
#include <wincrypt.h>

//#include <org/click3/dll_hack_lib.h>

HINTERNET authRequest = NULL;
const HINTERNET futenRequest = reinterpret_cast<HINTERNET>(0x45678900);
bool futenAvailable = false;

HINTERNET __stdcall d_WinHttpConnect(HINTERNET hSession, LPCWSTR pswzServerName, INTERNET_PORT nServerPort, DWORD dwReserved) {
  std::wcout << L"WinHttpConnect\n";
  std::wcout << pswzServerName << std::endl;
  return ::WinHttpConnect(hSession, pswzServerName, nServerPort, dwReserved);
}

HINTERNET __stdcall d_WinHttpOpenRequest(HINTERNET hConnect, LPCWSTR pwszVerb, LPCWSTR pwszObjectName, LPCWSTR pwszVersion, LPCWSTR pwszReferrer, LPCWSTR *ppwszAcceptTypes, DWORD dwFlags) {
  std::wcout << L"WinHttpOpenRequest\n";
  std::wcout << pwszObjectName << std::endl;
  if (std::wstring(L"/futen.cgi") == pwszObjectName) {
    futenAvailable = true;
    return futenRequest;
  }
  const HINTERNET result = ::WinHttpOpenRequest(hConnect, pwszVerb, pwszObjectName, pwszVersion, pwszReferrer, ppwszAcceptTypes, dwFlags);
  if (std::wstring(L"/v1/auth/") == pwszObjectName) {
    authRequest = result;
  }
  return result;
}

BOOL __stdcall d_WinHttpQueryDataAvailable(HINTERNET hRequest, LPDWORD lpdwNumberOfBytesAvailable) {
  std::wcout << L"WinHttpQueryDataAvailable\n";
  if (hRequest == futenRequest) {
    if (futenAvailable) {
      *lpdwNumberOfBytesAvailable = 204;
    } else {
      *lpdwNumberOfBytesAvailable = 0;
    }
    return TRUE;
  }
  const BOOL result = ::WinHttpQueryDataAvailable(hRequest, lpdwNumberOfBytesAvailable);
  std::wcout << *lpdwNumberOfBytesAvailable << std::endl;
  return result;
}

BOOL __stdcall d_WinHttpReadData(HINTERNET hRequest, LPVOID lpBuffer, DWORD dwNumberOfBytesToRead, LPDWORD lpdwNumberOfBytesRead) {
  static char sessionId[204] = {};
  std::wcout << L"WinHttpReadData\n";
  char * const buf = reinterpret_cast<char *>(lpBuffer);
  if (authRequest == hRequest &&  dwNumberOfBytesToRead == 203) {
    const BOOL result = ::WinHttpReadData(hRequest, sessionId, _countof(sessionId), lpdwNumberOfBytesRead);
    std::cout << std::string(&sessionId[0], &sessionId[*lpdwNumberOfBytesRead]) << std::endl;
    std::copy(&sessionId[0], &sessionId[*lpdwNumberOfBytesRead], stdext::checked_array_iterator<char *>(buf, dwNumberOfBytesToRead));
    return result;
  }
  if (futenRequest != hRequest || dwNumberOfBytesToRead != _countof(sessionId)) {
    return ::WinHttpReadData(hRequest, buf, dwNumberOfBytesToRead, lpdwNumberOfBytesRead);
  }
  futenAvailable = false;
  *lpdwNumberOfBytesRead = _countof(sessionId);
  std::copy(&sessionId[0], &sessionId[_countof(sessionId)], stdext::checked_array_iterator<char *>(buf, _countof(sessionId)));
  std::cout << std::string(&sessionId[0], &sessionId[*lpdwNumberOfBytesRead]) << std::endl;
  return TRUE;
}

BOOL __stdcall d_WinHttpSetTimeouts(HINTERNET hInternet, int nResolveTimeout, int nConnectTimeout, int nSendTimeout, int nReceiveTimeout) {
  std::wcout << L"WinHttpSetTimeouts\n";
  if (futenRequest == hInternet) {
    return TRUE;
  }
  return ::WinHttpSetTimeouts(hInternet, 2000, 2000, 2000, 2000);
}

BOOL __stdcall d_WinHttpSetCredentials(HINTERNET hRequest, DWORD AuthTargets, DWORD AuthScheme, LPCWSTR pwszUserName, LPCWSTR pwszPassword, LPVOID pAuthParams) {
  std::wcout << L"WinHttpSetCredentials\n";
  if (futenRequest == hRequest) {
    return TRUE;
  }
  return ::WinHttpSetCredentials(hRequest, AuthTargets, AuthScheme, pwszUserName, pwszPassword, pAuthParams);
}

BOOL __stdcall d_WinHttpSendRequest(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength, DWORD dwTotalLength, DWORD_PTR dwContext) {
  std::wcout << L"WinHttpSendRequest\n";
  std::wcout << lpszHeaders << std::endl;
  std::cout << reinterpret_cast<const char *>(lpOptional) << std::endl;
  if (futenRequest == hRequest) {
    return TRUE;
  }
  return ::WinHttpSendRequest(hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength, dwTotalLength, dwContext);
}

BOOL __stdcall d_WinHttpReceiveResponse(HINTERNET hRequest, LPVOID lpReserved) {
  std::wcout << L"WinHttpReceiveResponse\n";
  if (futenRequest == hRequest) {
    return TRUE;
  }
  return ::WinHttpReceiveResponse(hRequest, lpReserved);
}

BOOL __stdcall d_WinHttpQueryHeaders(HINTERNET hRequest, DWORD dwInfoLevel, LPCWSTR pwszName, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex) {
  std::wcout << L"WinHttpQueryHeaders\n";
  if (futenRequest == hRequest) {
    if ((WINHTTP_QUERY_FLAG_NUMBER | WINHTTP_QUERY_STATUS_CODE) == dwInfoLevel) {
      *reinterpret_cast<unsigned int *>(lpBuffer) = 200;
      return TRUE;
    }
    if (WINHTTP_QUERY_RAW_HEADERS_CRLF == dwInfoLevel) {
      static const wchar_t headers[] =
L"HTTP/1.1 200 OK\r\n"
L"Connection: close\r\n"
L"Content-Length: 204\r\n"
L"Content-Type: text/plain\r\n"
L"Server: Apache/2.2.15 (Unix) mod_ssl/2.2.15 OpenSSL/0.9.8n PHP/5.2.13\r\n"
L"Vary: Accept-Encoding\r\n"
L"X-Powered-By: PHP/5.2.13\r\n\r\n";
      if (lpBuffer == nullptr) {
        *lpdwBufferLength = sizeof(headers);
        ::SetLastError(ERROR_INSUFFICIENT_BUFFER);
        return FALSE;
      }
      std::copy(&headers[0], &headers[_countof(headers)], stdext::checked_array_iterator<wchar_t *>(reinterpret_cast<wchar_t *>(lpBuffer), *lpdwBufferLength));
      return TRUE;
    }
    return FALSE;
  }
  return ::WinHttpQueryHeaders(hRequest, dwInfoLevel, pwszName, lpBuffer, lpdwBufferLength, lpdwIndex);
}

BOOL __stdcall d_WinHttpCloseHandle(HINTERNET hInternet) {
  std::wcout << L"WinHttpCloseHandle\n";
  if (futenRequest == hInternet) {
    return TRUE;
  }
  return ::WinHttpCloseHandle(hInternet);
}

std::string getAccountCfgPath() {
  char filename[MAX_PATH];
  ::GetModuleFileNameA(NULL, filename, sizeof(filename));
  ::PathRemoveFileSpecA(filename);
  ::PathAppendA(filename, "account.cfg");
  return filename;
}

const HANDLE FIND_FILE_HANDLE_ACCOUNT_CFG = reinterpret_cast<HANDLE>(0x12345678);
const HANDLE FILE_HANDLE_ACCOUNT_CFG = reinterpret_cast<HANDLE>(0x23456789);
const char ACCOUNT_CFG_BODY[] = R"([RONIN]
UserID=dummy_id
Passwd=jAAAAAECAAACZgAAAKQAAEEu1+zneRKFw4kADrU8qOL96GlFjFktBZcIHHnKOR8hhGMnL7KDtAZ4jgC5t7Bnw0QfdVbB0fDAoWvfTNNOsYv4tXOB24pboFuAx9t4Nhxy+mjtDG4fApO3p2coum5yWJrEsRAnLKsv/wpjSHwVPcuimRhKmrmboDvTAwlCfa9OXDJ0gApOulM=
ALT=
AutoLogin=1
WriteLogin=0
)";
unsigned int ACCOUNT_CFG_POS = 0;

HANDLE __stdcall d_FindFirstFileA(const char * const lpFileName, WIN32_FIND_DATAA * const lpFindFileData) {
  if (getAccountCfgPath() == lpFileName) {
    SYSTEMTIME st;
    ::GetSystemTime(&st);
    WIN32_FIND_DATAA &fd = *lpFindFileData;
    fd.dwFileAttributes = FILE_ATTRIBUTE_READONLY;
    ::SystemTimeToFileTime(&st, &fd.ftCreationTime);
    ::SystemTimeToFileTime(&st, &fd.ftLastAccessTime);
    ::SystemTimeToFileTime(&st, &fd.ftLastWriteTime);
    fd.nFileSizeLow = sizeof(ACCOUNT_CFG_BODY);
    std::copy(&lpFileName[0], &lpFileName[::strlen(lpFileName)], stdext::checked_array_iterator<char *>(fd.cFileName, _countof(fd.cFileName)));
    return FIND_FILE_HANDLE_ACCOUNT_CFG;
  }
  return ::FindFirstFileA(lpFileName, lpFindFileData);
}
BOOL __stdcall d_FindClose(HANDLE hFindFile) {
  if (hFindFile == FIND_FILE_HANDLE_ACCOUNT_CFG) {
    return TRUE;
  }
  return FindClose(hFindFile);
}

HANDLE __stdcall d_CreateFileA(
  const char * const lpFileName,
  const DWORD dwDesiredAccess,
  const DWORD dwShareMode,
  SECURITY_ATTRIBUTES * const lpSecurityAttributes,
  const DWORD dwCreationDisposition,
  const DWORD dwFlagsAndAttributes,
  const HANDLE hTemplateFile)
{
  if (getAccountCfgPath() == lpFileName && dwDesiredAccess == GENERIC_READ) {
    ACCOUNT_CFG_POS = 0;
    return FILE_HANDLE_ACCOUNT_CFG;
  }
  return ::CreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}

BOOL __stdcall d_CloseHandle(const HANDLE handle) {
  if (handle == FILE_HANDLE_ACCOUNT_CFG) {
    return TRUE;
  }
  return ::CloseHandle(handle);
}

BOOL __stdcall d_ReadFile(const HANDLE hFile, void * const lpBuffer, const DWORD nNumberOfBytesToRead, DWORD * const lpNumberOfBytesRead, OVERLAPPED * const lpOverlapped) {
  if (hFile != FILE_HANDLE_ACCOUNT_CFG) {
    return ::ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
  }
  const unsigned int readSize = (std::min)(static_cast<unsigned int>(nNumberOfBytesToRead), sizeof(ACCOUNT_CFG_BODY) - ACCOUNT_CFG_POS);
  std::copy(
    &ACCOUNT_CFG_BODY[ACCOUNT_CFG_POS],
    &ACCOUNT_CFG_BODY[ACCOUNT_CFG_POS + readSize],
    stdext::checked_array_iterator<char *>(reinterpret_cast<char *>(lpBuffer), nNumberOfBytesToRead));
  if (lpNumberOfBytesRead != NULL) {
    *lpNumberOfBytesRead = readSize;
  }
  ACCOUNT_CFG_POS += readSize;
  return TRUE;
}

DWORD __stdcall d_SetFilePointer(const HANDLE hFile, const LONG lDistanceToMove, LONG * const lpDistanceToMoveHigh, const DWORD dwMoveMethod) {
  if (hFile != FILE_HANDLE_ACCOUNT_CFG) {
    return ::SetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
  }
  long long int distance = 0;
  if (lpDistanceToMoveHigh == nullptr) {
    distance = lDistanceToMove;
  } else {
    distance = static_cast<unsigned int>(lDistanceToMove) | (static_cast<long long int>(*lpDistanceToMoveHigh) << 32);
  }
  long long int cur = ACCOUNT_CFG_POS;
  long long int size = sizeof(ACCOUNT_CFG_BODY);
  unsigned long long int ptr = 0;
  switch (dwMoveMethod) {
  case FILE_BEGIN:
    ptr = (std::max)((std::min)(distance, size), 0LL);
    break;
  case FILE_CURRENT:
    ptr = (std::max)((std::min)(cur + distance, size), 0LL);
    break;
  case FILE_END:
    ptr = (std::max)((std::min)(size + distance, size), 0LL);
    break;
  default:
    return FALSE;
  }
  ACCOUNT_CFG_POS = static_cast<unsigned int>(ptr);
  if (lpDistanceToMoveHigh != NULL) {
    *lpDistanceToMoveHigh = (ptr >> 32);
  }
  return static_cast<DWORD>(ptr);
}

FARPROC __stdcall d_GetProcAddress(HMODULE hModule, LPCSTR lpProcName) {
  struct ProcMap {
    std::string name;
    const FARPROC proc;
  };
  static const std::vector<ProcMap> list = {
    {"WinHttpConnect", reinterpret_cast<FARPROC>(d_WinHttpConnect) },
    {"WinHttpOpenRequest", reinterpret_cast<FARPROC>(d_WinHttpOpenRequest) },
    {"WinHttpQueryDataAvailable", reinterpret_cast<FARPROC>(d_WinHttpQueryDataAvailable) },
    {"WinHttpReadData", reinterpret_cast<FARPROC>(d_WinHttpReadData) },
    {"WinHttpSetTimeouts", reinterpret_cast<FARPROC>(d_WinHttpSetTimeouts) },
    {"WinHttpSetCredentials", reinterpret_cast<FARPROC>(d_WinHttpSetCredentials) },
    {"WinHttpSendRequest", reinterpret_cast<FARPROC>(d_WinHttpSendRequest) },
    {"WinHttpReceiveResponse", reinterpret_cast<FARPROC>(d_WinHttpReceiveResponse) },
    {"WinHttpQueryHeaders", reinterpret_cast<FARPROC>(d_WinHttpQueryHeaders) },
    {"WinHttpCloseHandle", reinterpret_cast<FARPROC>(d_WinHttpCloseHandle) },
  };
  const auto it = std::find_if(list.begin(), list.end(), [lpProcName](const auto item) { return item.name == lpProcName; });
  if (it == list.end()) {
    return ::GetProcAddress(hModule, lpProcName);
  }
  return it->proc;
}

const HCRYPTKEY CRYPT_KEY_HANDLE_DUMMY = 0x34567890U;

BOOL __stdcall d_CryptImportKey(HCRYPTPROV  hProv, const BYTE *pbData, DWORD dwDataLen, HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey) {
  const BOOL result = ::CryptImportKey(hProv, pbData, dwDataLen, hPubKey, dwFlags, phKey);
  if (result == FALSE) {
    *phKey = CRYPT_KEY_HANDLE_DUMMY;
    return TRUE;
  }
  return result;
}

BOOL __stdcall d_CryptDecrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen) {
  if (hKey != CRYPT_KEY_HANDLE_DUMMY) {
    return ::CryptDecrypt(hKey, hHash, Final, dwFlags, pbData, pdwDataLen);
  }
  const char password[] = "a";
  std::copy(&password[0], &password[_countof(password)], stdext::checked_array_iterator<BYTE *>(pbData, *pdwDataLen));
  *pdwDataLen = ::strlen(password);
  return TRUE;
}

BOOL __stdcall d_CryptDestroyKey(HCRYPTKEY hKey) {
  if (hKey == CRYPT_KEY_HANDLE_DUMMY) {
    return TRUE;
  }
  return ::CryptDestroyKey(hKey);
}

bool ChangeIAT(HMODULE module) {
  static const struct {
    const std::string dllName;
    const std::string procName;
    const unsigned int procAddress;
  } targetList[] = {
    { "KERNEL32.dll", "FindFirstFileA", reinterpret_cast<unsigned int>(d_FindFirstFileA) },
    { "KERNEL32.dll", "FindClose", reinterpret_cast<unsigned int>(d_FindClose) },
    { "KERNEL32.dll", "CreateFileA", reinterpret_cast<unsigned int>(d_CreateFileA) },
    { "KERNEL32.dll", "CloseHandle", reinterpret_cast<unsigned int>(d_CloseHandle) },
    { "KERNEL32.dll", "ReadFile", reinterpret_cast<unsigned int>(d_ReadFile) },
    { "KERNEL32.dll", "SetFilePointer", reinterpret_cast<unsigned int>(d_SetFilePointer) },
    { "KERNEL32.dll", "GetProcAddress", reinterpret_cast<unsigned int>(d_GetProcAddress) },
    { "ADVAPI32.dll", "CryptDecrypt", reinterpret_cast<unsigned int>(d_CryptDecrypt) },
    { "ADVAPI32.dll", "CryptImportKey", reinterpret_cast<unsigned int>(d_CryptImportKey) },
    { "ADVAPI32.dll", "CryptDestroyKey", reinterpret_cast<unsigned int>(d_CryptDestroyKey) },
  };
  unsigned char * const baseAddr = reinterpret_cast<unsigned char *>(module == NULL ? ::GetModuleHandleW(NULL) : module);
  const IMAGE_DOS_HEADER &mz = *reinterpret_cast<const IMAGE_DOS_HEADER *>(baseAddr);
  const IMAGE_NT_HEADERS32 &pe = *reinterpret_cast<const IMAGE_NT_HEADERS32 *>(baseAddr + mz.e_lfanew);
  const IMAGE_IMPORT_DESCRIPTOR *desc = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR *>(baseAddr + pe.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
  if (desc->OriginalFirstThunk == 0) { // IATがない場合
    struct AddressMapItem {
      unsigned int original;
      unsigned int dummy;
    };
    std::vector<AddressMapItem> addressMap(_countof(targetList));
    for (const unsigned int i : boost::irange(0U, _countof(targetList))) {
      const auto &target = targetList[i];
      addressMap[i].original = reinterpret_cast<unsigned int>(::GetProcAddress(::GetModuleHandleA(target.dllName.c_str()), target.procName.c_str()));
      addressMap[i].dummy = target.procAddress;
    }
    for (; desc->Name != 0; desc++) {
      const char * const dllName = reinterpret_cast<const char *>(baseAddr + desc->Name);
      unsigned int *out = reinterpret_cast<unsigned int *>(baseAddr + desc->FirstThunk);
      for (; *out != 0; out++) {
        const auto it = std::find_if(addressMap.begin(), addressMap.end(), [out](const auto item) {
          return item.original == *out;
        });
        if (it != addressMap.end()) {
          DWORD oldProtect;
          ::VirtualProtect(out, 4, PAGE_READWRITE, &oldProtect);
          *out = it->dummy;
          ::VirtualProtect(out, 4, oldProtect, &oldProtect);
        }
      }
    }
    return true;
  }
  for (; desc->OriginalFirstThunk != 0; desc = ++desc) {
    const char * const dllName = reinterpret_cast<const char *>(baseAddr + desc->Name);
    const unsigned int *in = reinterpret_cast<unsigned int *>(baseAddr + desc->OriginalFirstThunk);
    unsigned int *out = reinterpret_cast<unsigned int *>(baseAddr + desc->FirstThunk);
    for (; *in != 0; ++in, ++out) {
      if ((*in & 0x80000000) != 0) {
        continue;
      }
      const char * const procName = reinterpret_cast<const char *>(baseAddr + *in + 2);
      for (const auto &target : targetList) {
        if (::_stricmp(target.dllName.c_str(), dllName) != 0 || target.procName != procName) {
          continue;
        }
        DWORD oldProtect;
        ::VirtualProtect(out, 4, PAGE_READWRITE, &oldProtect);
        *out = target.procAddress;
        ::VirtualProtect(out, 4, oldProtect, &oldProtect);
      }
    }
  }
  return true;
}

void main() {
  //::org::click3::DllHackLib::SetupConsole();
  ChangeIAT(NULL);
}