/*
 * To build, set up your Release configuration like this:
 *
 * [Runtime Library]
 * Multi-threaded (/MT)
 *
 * Visit https://frida.re to learn more about Frida.
 */

#include "frida-gumjs.h"

#include <windows.h>

static void on_message (const gchar * message, GBytes * data, gpointer user_data);

int
main (int argc,
      char * argv[])
{
  GumScriptBackend * backend;
  GCancellable * cancellable = NULL;
  GError * error = NULL;
  GumScript * script;
  GMainContext * context;

  gum_init_embedded ();

  backend = gum_script_backend_obtain_qjs ();

  script = gum_script_backend_create_sync (backend, "example",
      "Interceptor.attach(Process.getModuleByName('user32.dll').getExportByName('MessageBeep'), {\n"
      "  onEnter(args) {\n"
      "    console.log(`[*] MessageBeep(${args[0].toInt32()})`);\n"
      "  }\n"
      "});\n"
      "Interceptor.attach(Process.getModuleByName('kernel32.dll').getExportByName('Sleep'), {\n"
      "  onEnter(args) {\n"
      "    console.log(`[*] Sleep(${args[0].toInt32()})`);\n"
      "  }\n"
      "});",
      NULL, cancellable, &error);
  g_assert (error == NULL);

  gum_script_set_message_handler (script, on_message, NULL, NULL);

  gum_script_load_sync (script, cancellable);

  MessageBeep (MB_ICONINFORMATION);
  Sleep (1);

  context = g_main_context_get_thread_default ();
  while (g_main_context_pending (context))
    g_main_context_iteration (context, FALSE);

  gum_script_unload_sync (script, cancellable);

  g_object_unref (script);

  gum_deinit_embedded ();

  return 0;
}

static void
on_message (const gchar * message,
            GBytes * data,
            gpointer user_data)
{
  JsonParser * parser;
  JsonObject * root;
  const gchar * type;

  parser = json_parser_new ();
  json_parser_load_from_data (parser, message, -1, NULL);
  root = json_node_get_object (json_parser_get_root (parser));

  type = json_object_get_string_member (root, "type");
  if (strcmp (type, "log") == 0)
  {
    const gchar * log_message;

    log_message = json_object_get_string_member (root, "payload");
    g_print ("%s\n", log_message);
  }
  else
  {
    g_print ("on_message: %s\n", message);
  }

  g_object_unref (parser);
}
