備忘録

備忘録

systemdを利用してCPU使用率を制限する方法

Ⅰ. はじめに

タイトルの通り「systemdを利用してCPU使用率を制限する方法」です。

Ⅱ. やり方

1. 負荷テスト用にstressをインストールする
apt install stress
2. systemd ユニットファイルを作成する

/etc/systemd/system/StressTest.service

[Unit]
Description=StressTest

[Service]
ExecStart=stress --cpu 4 --timeout 3s
# 1コア約80%までに制限。4コアある場合は4 * 80% = 320%を指定する
CPUQuota=320%

[Install]
WantedBy=multi-user.target
3. 開始する
systemctl start StressTest

実行結果

stressコマンドは本来CPU使用率が100%になるが約80%に収まっている。
f:id:kagasu:20210326154158p:plain

Linuxで任意CA証明書をインストールする方法

Ⅰ. はじめに

タイトルの通り「Linuxで任意CA証明書をインストールする方法」です。

Ⅱ. やり方

1. 任意CA証明書をコピーする
cp server.crt /usr/local/share/ca-certificates/
2. 更新する
update-ca-certificates

Linuxで自己署名証明書を発行する方法

Ⅰ. はじめに

タイトルの通り「Linux自己署名証明書を発行する方法」です。
オレオレ証明書とも呼ばれる事があります。

Ⅱ. やり方

1. 秘密鍵生成(RSA 2048bit)
openssl genrsa 2048 > server.key
2. 証明書署名要求(CSR)の生成
openssl req -new -key server.key > server.csr
3. CA証明書生成
openssl x509 -req -days 3650 -signkey server.key < server.csr > server.crt

その他

C++でWindows上の特定プロセスの全モジュールを取得する方法

Ⅰ. はじめに

タイトルの通り「C++Windows上の特定プロセスの全モジュールを取得する方法」です。

Ⅱ. サンプルプログラム1(EnumProcessModulesExを使用する方法)

#include <windows.h>
#include <Psapi.h>
#include <iostream>

void ShowAllModules(uint32_t processId)
{
  HMODULE hMods[1024];

  auto processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
  if (processHandle != nullptr)
  {
    DWORD cbNeeded;
    if (EnumProcessModulesEx(processHandle, hMods, sizeof(hMods), &cbNeeded, LIST_MODULES_ALL))
    {
      for (uint32_t i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
      {
        wchar_t filePath[MAX_PATH];

        if (GetModuleFileNameEx(processHandle, hMods[i], filePath, sizeof(filePath) / sizeof(wchar_t)))
        {
          std::wcout << "BaseAddress: 0x" << hMods[i] << std::endl;
          std::wcout << "FilePath: " << filePath << std::endl;
        }
      }
    }
    CloseHandle(processHandle);
  }
}

int main(void)
{
  auto processId = 1234;
  ShowAllModules(processId);

  return 0;
}

Ⅲ. サンプルプログラム2(CreateToolhelp32Snapshotを使用する方法)

#include <windows.h>
#include <Psapi.h>
#include <TlHelp32.h>
#include <iostream>

void ShowAllModules(uint32_t processId)
{
  MODULEENTRY32 moduleEntry32 = { 0 };

  auto processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
  if (processHandle != nullptr)
  {
    auto hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processId);
    if (hThreadSnap != INVALID_HANDLE_VALUE)
    {
      moduleEntry32.dwSize = sizeof(MODULEENTRY32);

      if (!Module32First(hThreadSnap, &moduleEntry32))
      {
        std::cout << "failed" << std::endl;
      }
      else
      {
        do
        {
          wchar_t filePath[MAX_PATH];
          GetModuleFileNameEx(processHandle, moduleEntry32.hModule, filePath, MAX_PATH);
          std::wcout << "BaseAddress: 0x" << moduleEntry32.modBaseAddr << std::endl;
          std::wcout << "FilePath: " << filePath << std::endl;
        } while (Module32Next(hThreadSnap, &moduleEntry32));
      }
      CloseHandle(hThreadSnap);
    }
    CloseHandle(processHandle);
  }
}

int main(void)
{
  auto processId = 1234;
  ShowAllModules(processId);

  return 0;
}

Ⅳ. サンプルプログラム3(NtQueryInformationProcessを使用する方法)

※対象がWOW64プロセスの場合はNtWow64QueryInformationProcess64を使用します。

#include <windows.h>
#include <winternl.h>
#include <iostream>

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

void ShowAllModules(uint32_t processId)
{
  auto moduleHandle = LoadLibrary(L"ntdll.dll");
  if (moduleHandle != nullptr)
  {
    auto pNtQueryInformationProcess = reinterpret_cast<decltype(&NtQueryInformationProcess)>(GetProcAddress(moduleHandle, "NtQueryInformationProcess"));

    auto processHandle = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
    if (processHandle != nullptr)
    {
      PROCESS_BASIC_INFORMATION pbi = { 0 };
      if (NT_SUCCESS(pNtQueryInformationProcess(processHandle, PROCESSINFOCLASS::ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), nullptr)))
      {
        if (pbi.PebBaseAddress != nullptr)
        {
          PEB peb = { 0 };
          ReadProcessMemory(processHandle, pbi.PebBaseAddress, &peb, sizeof(PEB), nullptr);

          PEB_LDR_DATA pebLdrData = { 0 };
          ReadProcessMemory(processHandle, peb.Ldr, &pebLdrData, sizeof(PEB_LDR_DATA), nullptr);

          auto pModuleFirstEntry = pebLdrData.InMemoryOrderModuleList.Flink;
          auto pModuleCurrentEntry = pebLdrData.InMemoryOrderModuleList.Flink;
          do
          {
            auto pLdrDataTableEntry = CONTAINING_RECORD(pModuleCurrentEntry, LDR_DATA_TABLE_ENTRY, LDR_DATA_TABLE_ENTRY::InMemoryOrderLinks);

            LDR_DATA_TABLE_ENTRY ldrDataTableEntry = { 0 };
            ReadProcessMemory(processHandle, pLdrDataTableEntry, &ldrDataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY), nullptr);

            wchar_t str[MAX_PATH];
            ReadProcessMemory(processHandle, ldrDataTableEntry.FullDllName.Buffer, &str, ldrDataTableEntry.FullDllName.Length, nullptr);
            auto filePath = std::wstring(str, ldrDataTableEntry.FullDllName.Length / sizeof(wchar_t));

            if (ldrDataTableEntry.DllBase != nullptr)
            {
              std::wcout << "BaseAddress: 0x" << ldrDataTableEntry.DllBase << std::endl;
              std::wcout << "FilePath: " << filePath << std::endl;
            }

            pModuleCurrentEntry = ldrDataTableEntry.InMemoryOrderLinks.Flink;
          } while (pModuleCurrentEntry != pModuleFirstEntry);
        }
      }
      CloseHandle(processHandle);
    }

    FreeModule(moduleHandle);
  }
}

int main(void)
{
  auto processId = 1234;
  ShowAllModules(processId);

  return 0;
}

Ⅴ. 実行結果

BaseAddress: 0x00007FF699110000
FilePath: C:\WINDOWS\system32\notepad.exe
BaseAddress: 0x00007FFBCE1F0000
FilePath: C:\WINDOWS\SYSTEM32\ntdll.dll
BaseAddress: 0x00007FFBCE0F0000
FilePath: C:\WINDOWS\System32\KERNEL32.DLL
BaseAddress: 0x00007FFBCBC10000
FilePath: C:\WINDOWS\System32\KERNELBASE.dll
...
(以下省略)

Ⅵ. 留意点

  • WOW64プロセスから64bitプロセスの情報を取得する事は出来ません。(参考1)
  • NtQueryInformationProcessは非公開APIなので一般向きでは無いです。
  • 私の環境では全て同じ実行結果が得られました。
    使用しているAPIが異なる為実行結果が異なる可能性があります。
    ※一部モジュールが正しく取得できない等。

C++でWindows上の特定プロセスの全スレッドIDを取得する方法

Ⅰ. はじめに

タイトルの通り「C++Windows上の特定プロセスの全スレッドIDを取得する方法」です。

Ⅱ. サンプルプログラム

#include <Windows.h>
#include <tlhelp32.h>
#include <iostream>
#include <vector>
#include <algorithm>

std::vector<uint32_t> GetAllThreadIds(uint32_t processId)
{
  std::vector<uint32_t> threadIds;
  THREADENTRY32 threadEntry32 = { 0 };

  auto hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, processId);
  if (hThreadSnap != INVALID_HANDLE_VALUE)
  {
    threadEntry32.dwSize = sizeof(THREADENTRY32);

    if (!Thread32First(hThreadSnap, &threadEntry32))
    {
      CloseHandle(hThreadSnap);
    }
    else
    {
      do
      {
        if (threadEntry32.th32OwnerProcessID == processId)
        {
          threadIds.emplace_back(threadEntry32.th32ThreadID);
        }
      } while (Thread32Next(hThreadSnap, &threadEntry32));

      CloseHandle(hThreadSnap);
    }
  }

  return threadIds;
}

int main()
{
  auto pid = GetCurrentProcessId();
  auto threadIds = GetAllThreadIds(pid);
  std::sort(threadIds.begin(), threadIds.end());
  for (auto threadId : threadIds)
  {
    std::cout << "threadId: " << threadId << std::endl;
  }

  return 0;
}

実行結果

f:id:kagasu:20210305114445p:plain