1

I was wondering what this function here does:

  ralloc_t(HWND hwnd) : proc_(0)
  {
    DWORD pid = 0;
    if (!GetWindowThreadProcessId(hwnd, &pid)) {
      throw exception("dang, no dice");
    }
    proc_ = OpenProcess(
        PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
    if (!proc_) {
      throw exception("no open for me!");
    }
  }
  ~ralloc_t()
  {
    buffers_t::reverse_iterator i = buffers_.rbegin(), e = buffers_.rend();
    for (; i != e; ++i) {
      free(i->first);
    }
  }

I honestly don't know where function starts and where it ends and if it's returning anything.

The full code is below. I got a decent start on it, in that I have all the winapi functions in use below converted already to js-ctypes. This is what I have so far: https://gist.github.com/Noitidart/f691ab9a750f24be346f

#include <windows.h>
#include <commctrl.h>

#include <iostream>
#include <cstdio>
#include <stdexcept>
#include <map>

using namespace std;

/**
 * Allocate/read/write remote process memory.
 * The implementation is pretty crappy, as it isn't intelligent at all:
 * It always allocates at least a full page per allocation :(
 * Do something more clever in production!
 * Also, type safety and convenience are pretty lacking.
 * But again, this is test code, so it sucks!
 */
class ralloc_t
{
public:
  ralloc_t(HWND hwnd) : proc_(0)
  {
    DWORD pid = 0;
    if (!GetWindowThreadProcessId(hwnd, &pid)) {
      throw exception("dang, no dice");
    }
    proc_ = OpenProcess(
        PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
    if (!proc_) {
      throw exception("no open for me!");
    }
  }
  ~ralloc_t()
  {
    buffers_t::reverse_iterator i = buffers_.rbegin(), e = buffers_.rend();
    for (; i != e; ++i) {
      free(i->first);
    }
  }
  void* alloc(size_t size)
  {
    void* rv = VirtualAllocEx(
        proc_, 0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!rv) {
      throw bad_alloc();
    }
    buffers_.insert(make_pair(rv, size));
    return rv;
  }
  template <typename T>
  T* create(size_t elems = 1)
  {
    return (T*)alloc(elems * sizeof(T));
  }

  void free(void* p)
  {
    buffers_t::iterator i = buffers_.find(p);
    if (i == buffers_.end()) {
      throw exception("invalid buffer");
    }
    VirtualFreeEx(proc_, i->first, i->second, MEM_RELEASE);
    buffers_.erase(i);
  }

  void read(void* remote, void* local)
  {
    buffers_t::iterator i = buffers_.find(remote);
    if (i == buffers_.end()) {
      throw exception("invalid remote read buffer");
    }
    if (!ReadProcessMemory(proc_, i->first, local, i->second, 0)) {
      throw exception("failed to read remote buffer");
    }
  }

  void write(void* remote, const void* local)
  {
    buffers_t::iterator i = buffers_.find(remote);
    if (i == buffers_.end()) {
      throw exception("invalid remote write buffer");
    }
    if (!WriteProcessMemory(proc_, i->first, local, i->second, 0)) {
      throw exception("failed to write remote buffer");
    }
  }

private:
  typedef map<void*, size_t> buffers_t;
  buffers_t buffers_;
  HANDLE proc_;
};

int main()
{
  typedef HWND(WINAPI * GetTaskmanWindowPtr)();
  try
  {
    HMODULE user32 = LoadLibrary(L"user32");
    GetTaskmanWindowPtr GetTaskmanWindow =
        (GetTaskmanWindowPtr)GetProcAddress(user32, "GetTaskmanWindow");
    if (!GetTaskmanWindow) {
      throw exception("Failed to get GetTaskmanWindow!");
    }
    HWND htm = GetTaskmanWindow();
    if (!htm) {
      throw exception("Failed to get taskman window");
    }
    HWND htb = FindWindowEx(htm, 0, L"ToolbarWindow32", 0);
    if (!htb) {
      throw exception("Failed to get toolbar window");
    }
    ralloc_t ralloc(htb);
    int count = SendMessage(htb, TB_BUTTONCOUNT, 0, 0);
    cout << count << endl;

    for (int i = 0; i < count; ++i) {
      TBBUTTON tbb;
      TBBUTTON* rtbb = ralloc.create<TBBUTTON>();
      BOOL rv = SendMessage(htb, TB_GETBUTTON, i, (LPARAM)rtbb);
      ralloc.read(rtbb, &tbb);
      ralloc.free(rtbb);
      cout << rv << " " << sizeof(tbb) << " " << tbb.idCommand << " "
           << tbb.iString << endl << flush;

      int chars = SendMessage(htb, TB_GETBUTTONTEXT, tbb.idCommand, (LPARAM)0);
      if (chars <= 0) {
        continue;
      }
      chars++;
      wchar_t* rbuf = ralloc.create<wchar_t>(chars);
      if (SendMessage(htb, TB_GETBUTTONTEXT, tbb.idCommand, (LPARAM)rbuf) > 0) {
        wchar_t* buf = new wchar_t[chars];
        ralloc.read(rbuf, buf);
        wcout << buf << endl << flush;
        delete[] buf;
      }
    }
  }
  catch (const exception& ex)
  {
    cerr << "Error: " << ex.what() << endl;
  }

  // Sleep
  getchar();
  return 0;
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Noitidart
  • 35,443
  • 37
  • 154
  • 323

1 Answers1

2

It seems you need to learn about classes in C++. What you are looking at is two functions. The first is called ralloc_t and is the class's constructor. The second is called ~ralloc_t and is the class's destructor.

  // This is the constructor
  ralloc_t(HWND hwnd) : proc_(0)
  {
    DWORD pid = 0;
    if (!GetWindowThreadProcessId(hwnd, &pid)) {
      throw exception("dang, no dice");
    }
    proc_ = OpenProcess(
        PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, pid);
    if (!proc_) {
      throw exception("no open for me!");
    }
  }

  // This is the destructor
  ~ralloc_t()
  {
    buffers_t::reverse_iterator i = buffers_.rbegin(), e = buffers_.rend();
    for (; i != e; ++i) {
      free(i->first);
    }
  }

Note that the constructor has the same name as the class (see the line class ralloc_t), and the destructor has the same name but prefixed with a tilde (~).

These functions, by their very nature, do not return anything. The purpose of the constructor is to initialise objects of type ralloc_t when they are constructed, and the purpose of the destructor is to clean up when they are destroyed.

For example, you might have a block of code that looks something like this:

{
  ralloc_t my_ralloc(some_hwnd);
  // ...
}

The constructor gets called as a result of the declaration of my_ralloc (passing some_hwnd as the constructor's argument). The destructor will get called at the end of the block, which is when the variable goes out of scope and is destroyed.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • Thank you very much for your quick lesson! This will help me out a lot! I really appreciate it. I'll look up some stuff on classes right now. – Noitidart Jun 21 '14 at 09:08
  • 1
    @Noitidart I edited my answer with some further information that might help. – Joseph Mansfield Jun 21 '14 at 09:11
  • @Noitidart Since you're trying to recreate the behaviour in JavaScript, you'll also need to know [how to implement "classes" in JS](http://stackoverflow.com/a/387733/150634) too. – Joseph Mansfield Jun 21 '14 at 09:16
  • Thanks very much! Would you be free to chat for like 10min about this? My question right now was is `r_alloc` doing something to `htb` before being fed into `SendMessage`. In code here: `ralloc_t ralloc(htb); int count = SendMessage(htb, TB_BUTTONCOUNT, 0, 0);` I think I'm a javascript master, not guru but pretty good at it I got that stuff down thanks for the link though! :) – Noitidart Jun 21 '14 at 09:17
  • @Noitidart Well, it isn't being fed into `SendMessage`. The `ralloc_t` object that is being created is called `ralloc`, and you don't see `ralloc` in the `SendMessage` call, do you? Despite this, yes, the `ralloc_t` object is doing something when it is constructed. – Joseph Mansfield Jun 21 '14 at 09:22
  • Ah you're very right, I see now that `ralloc` is not going in. So does `ralloc_t` like "allocate" I have to go look up what that word means. So like memory allows the `SendMessage` to happen without crashing? – Noitidart Jun 21 '14 at 09:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/56016/discussion-between-noitidart-and-joseph-mansfield). – Noitidart Jun 21 '14 at 09:28
  • @Noitidart I don't know much about the Windows API, but as far as I can tell, this class provides an interface for managing the memory of a different process. To use the class, you construct an object with `ralloc_t ralloc(htb);`, where `htb` is a `HWND` denoting a window of the process you want to manage the memory of. You can then use the functions `alloc`, `free`, `read`, and `write`, to allocate, free, read, and write the memory of that process. These are called as member functions. For example, if you wanted to allocate 4 bytes, you would do `ralloc.alloc(4);`. – Joseph Mansfield Jun 21 '14 at 09:29
  • 1
    Accepted solution, he graciously spent so much time with over SO chat! :) Thanks Joseph!! – Noitidart Jun 21 '14 at 10:08
  • Oh my gosh thank you Joseph for all your help!!! I FINALLY got it what an intesnt 24+ hours haha: https://gist.github.com/Noitidart/f691ab9a750f24be346f – Noitidart Jun 22 '14 at 08:44