2

I ran dtruss on a process that launches another one: the League of Legends Launcher starts the main game process with certain arguments that I can't seem to pass via the command line.

What caught my attention was this line of dtruss output:

PID/THRD  RELATIVE  ELAPSD    CPU SYSCALL(args)          = return
9386/0x47dac:     19625    3013   1805 posix_spawn(0x2A634FC, 0x38A2A00, 0xB06A56E0)         = 0 0

I looked up the man page for posix_spawn, and it is supposed to accept 6 arguments. They are, in order, PID, /path/to/file, file_actions, aatrp, argv and envp.

I was stepping through GDB at the same time as running dtruss, so I was able to inspect the memory in question.

  • The first argument pointed to 0x000024d2, which was in the PID.
  • The second argument pointed to a char array: the executable path for LeagueofLegends
  • The third argument always points to the same thing, of which the unintelligible string representation is \026l<?

I don't know what to make of this. Ultimately I want to be able to launch this process myself via C, with my custom arguments, but I think the first step to do that is to understand how it's called by the system, and what that third argument is.

My questions are: what more can I do to find out what that third argument is (?) and is what I'm trying to do (circumventing the launcher) even possible?

It is possible directly on the Windows command-line via,

 @start "" "League of Legends.exe" "8394" "LoLLauncher.exe" "" "spectator fspectate.op.gg:4081 tjJbtRLQ/HMV7HuAxWV0XsXoRB4OmFBr 1391881421 NA1"

but on Mac this just relaunches the launcher.

For context, I've already written up a lengthy (and unanswered) question describing everything I've done.

Please let me know how I can improve this question. I've spent over 50 hours trying to figure this out on my own, brute forcing through dtruss output, and I'm just about ready to give up.

1 Answers1

0

If you read the source code for dtruss:

cat `which dtruss`

You'll discover that the number of arguments is hard-coded.

Entry:

 syscall:::entry
 /(OPT_command && pid == $target) || 
  (OPT_pid && pid == PID) ||
  (OPT_name && NAME == strstr(NAME, execname)) ||
  (OPT_name && execname == strstr(execname, NAME)) ||
  (self->child)/
 {
    /* set start details */
    self->start = timestamp;
    self->vstart = vtimestamp;
    self->arg0 = arg0;
    self->arg1 = arg1;
    self->arg2 = arg2;

    /* count occurances */
    OPT_counts == 1 ? @Counts[probefunc] = count() : 1;
 }

Return:

 /* print 3 arg output - default */
 syscall:::return
 /self->start/
 {
    /* calculate elapsed time */
    this->elapsed = timestamp - self->start;
    self->start = 0;
    this->cpu = vtimestamp - self->vstart;
    self->vstart = 0;
    self->code = errno == 0 ? "" : "Err#";

    /* print optional fields */
    /* OPT_printid  ? printf("%5d/%d:  ",pid,tid) : 1; */
    OPT_printid  ? printf("%5d/0x%x:  ",pid,tid) : 1;
    OPT_relative ? printf("%8d ",vtimestamp/1000) : 1;
    OPT_elapsed  ? printf("%7d ",this->elapsed/1000) : 1;
    OPT_cpu      ? printf("%6d ",this->cpu/1000) : 1;

    /* print main data */
    printf("%s(0x%X, 0x%X, 0x%X)\t\t = %d %s%d\n",probefunc,self->arg0,
        self->arg1,self->arg2,(int)arg0,self->code,(int)errno);
    OPT_stack ? ustack()    : 1;
    OPT_stack ? trace("\n") : 1;
    self->arg0 = 0;
    self->arg1 = 0;
    self->arg2 = 0;
 }

Certain syscalls have bespoke handling (/* mmap has 6 arguments */).

I made a copy of the script and copy-pasted in a few more self->arg* and , 0x%X.

I was able to change the default to 6 args, achieving output like this:

posix_spawn(0x700003AA66B4, 0x7FF7B215BF10, 0x700003AA6570, 0x700003AA6610, 0x700003AA6720, 0x0)         = 0 0

As for why we have to copy-paste args instead of just incrementing a counter: DTrace does not support loops. I think because it's unacceptable for tracing to introduce the possibility of an infinite loop inside the kernel.

Birchlabs
  • 141