/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;
import java.lang.reflect.*;
import java.io.*;
import java.util.*;
import sun.misc.*;

public class ApiMonitor {

 private static int handler_code[]={
  0x4f222fe6,     /*  mov.l   r14, @-r15                                      */
                  /*  sts.l   pr, @-r15                                       */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x0009b061,     /*  bsr     forward                                         */
                  /*  nop                                                     */
  0x11223344,     /*  .long 0x11223344                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x00000000,     /*  .long 0x00000000                                        */
                  /*                                                          */
  0x2f864f22,     /*  sts.l   pr, @-r15                                       */
                  /*  mov.l   r8, @-r15                                       */
  0x2fa62f96,     /*  mov.l   r9, @-r15                                       */
                  /*  mov.l   r10, @-r15                                      */
  0x50892fb6,     /*  mov.l   r11, @-r15                                      */
                  /*  mov.l   @(mutex_lock_off,r8),r0        ! mutex_lock     */
  0x348ce418,     /*  mov     #mutex_off,r4                                   */
                  /*  add     r8,r4                                           */
  0x400b6442,     /*  mov.l   @r4,r4                         ! mutex          */
                  /*  jsr     @r0                                             */
  0xe0010009,     /*  nop                                                     */
                  /*  mov     #1,r0                                           */
  0x318ce140,     /*  mov     #preq_off,r1                                    */
                  /*  add     r8,r1                                           */
  0xe0302102,     /*  mov.l   r0,@r1                         ! pending request*/
                  /*  mov     #cond_signal_off,r0                             */
  0x6002308c,     /*  add     r8,r0                                           */
                  /*  mov.l   @r0,r0                         ! cond_signal    */
  0x348ce41c,     /*  mov     #request_off,r4                                 */
                  /*  add     r8,r4                                           */
  0x400b6442,     /*  mov.l   @r4,r4                         ! request        */
                  /*  jsr     @r0                                             */
  0xe1440009,     /*  nop                                                     */
                  /*  mov     #presp_off,r1                                   */
  0x6012318c,     /*  add     r8,r1                                           */
                  /*  mov.l   @r1,r0                         ! pending respons*/
  0x8b0b2008,     /*  tst     r0,r0                                           */
                  /*  bf      hasresponse                                     */
  0x508b0009,     /*  nop                                                     */
                  /*  mov.l   @(cond_wait_off,r8),r0         ! cond_wait      */
  0x348ce420,     /*  mov     #response_off,r4                                */
                  /*  add     r8,r4                                           */
  0xe5186442,     /*  mov.l   @r4,r4                         ! response       */
                  /*  mov     #mutex_off,r5                                   */
  0x6552358c,     /*  add     r8,r5                                           */
                  /*  mov.l   @r5,r5                         ! mutex          */
  0x0009400b,     /*  jsr     @r0                                             */
                  /*  nop                                                     */
  0x0009afef,     /*  bra     waitresponse                                    */
                  /*  nop                                                     */
  0xe144e000,     /*  mov     #0,r0                                           */
                  /*  mov     #presp_off,r1                                   */
  0x2102318c,     /*  add     r8,r1                                           */
                  /*  mov.l   r0,@r1                         ! pending respons*/
  0xe418508a,     /*  mov.l   @(mutex_unlock_off,r8),r0      ! mutex_unlock   */
                  /*  mov     #mutex_off,r4                                   */
  0x6442348c,     /*  add     r8,r4                                           */
                  /*  mov.l   @r4,r4                         ! mutex          */
  0x0009400b,     /*  jsr     @r0                                             */
                  /*  nop                                                     */
  0x6af66bf6,     /*  mov.l   @r15+, r11                                      */
                  /*  mov.l   @r15+, r10                                      */
  0x68f669f6,     /*  mov.l   @r15+, r9                                       */
                  /*  mov.l   @r15+, r8                                       */
  0x000b4f26,     /*  lds.l   @r15+, pr                                       */
                  /*  rts                                                     */
  0x2f160009,     /*  nop                                                     */
                  /*  mov.l   r1, @-r15                                       */
  0x2f262f16,     /*  mov.l   r1, @-r15                                       */
                  /*  mov.l   r2, @-r15                                       */
  0x2f462f36,     /*  mov.l   r3, @-r15                                       */
                  /*  mov.l   r4, @-r15                                       */
  0x2f662f56,     /*  mov.l   r5, @-r15                                       */
                  /*  mov.l   r6, @-r15                                       */
  0x2f862f76,     /*  mov.l   r7, @-r15                                       */
                  /*  mov.l   r8, @-r15                                       */
  0x2fa62f96,     /*  mov.l   r9, @-r15                                       */
                  /*  mov.l   r10, @-r15                                      */
  0x2fc62fb6,     /*  mov.l   r11, @-r15                                      */
                  /*  mov.l   r12, @-r15                                      */
  0xe0142fd6,     /*  mov.l   r13, @-r15                                      */
                  /*  mov     #20,r0                                          */
  0x6ef33f08,     /*  sub     r0,r15                                          */
                  /*  mov     r15, r14                                        */
  0x2f46082a,     /*  sts     pr,r8                                           */
                  /*  mov.l   r4, @-r15                                       */
  0x2f662f56,     /*  mov.l   r5, @-r15                                       */
                  /*  mov.l   r6, @-r15                                       */
  0x50892f76,     /*  mov.l   r7, @-r15                                       */
                  /*  mov.l   @(mutex_lock_off,r8),r0        ! mutex_lock     */
  0x348ce414,     /*  mov     #gmutex_off,r4                                  */
                  /*  add     r8,r4                                           */
  0x400b6442,     /*  mov.l   @r4,r4                         ! mutex          */
                  /*  jsr     @r0                                             */
  0x50810009,     /*  nop                                                     */
                  /*  mov.l   @(malloc_off,r8),r0            ! malloc         */
  0x400be420,     /*  mov     #32,r4                                          */
                  /*  jsr     @r0                                             */
  0x69030009,     /*  nop                                                     */
                  /*  mov     r0,r9                                           */
  0x308ce038,     /*  mov     #ptr_off,r0                                     */
                  /*  add     r8,r0                                           */
  0x67f62092,     /*  mov.l   r9,@r0                         ! store ptr      */
                  /*  mov.l   @r15+, r7                      ! reload r4-r7   */
  0x65f666f6,     /*  mov.l   @r15+, r6                                       */
                  /*  mov.l   @r15+, r5                                       */
  0x609364f6,     /*  mov.l   @r15+, r4                                       */
                  /*  mov     r9,r0                          ! store regs     */
  0x70042042,     /*  mov.l   r4,@r0                                          */
                  /*  add     #4,r0                                           */
  0x70042052,     /*  mov.l   r5,@r0                                          */
                  /*  add     #4,r0                                           */
  0x70042062,     /*  mov.l   r6,@r0                                          */
                  /*  add     #4,r0                                           */
  0x70042072,     /*  mov.l   r7,@r0                                          */
                  /*  add     #4,r0                                           */
  0x32ece24c,     /*  mov     #76,r2                         ! offset of retur*/
                  /*  add     r14,r2                                          */
  0xe3486222,     /*  mov.l   @r2,r2                         ! return addr    */
                  /*  mov     #raddr_off,r3                                   */
  0x2322338c,     /*  add     r8,r3                                           */
                  /*  mov.l   r2,@r3                         ! store return ad*/
  0xe2547304,     /*  add     #4,r3                                           */
                  /*  mov     #84,r2                         ! top of stack   */
  0x232232ec,     /*  add     r14,r2                                          */
                  /*  mov.l   r2,@r3                         ! store stack poi*/
  0x20326326,     /*  mov.l   @r2+,r3                        ! arg4           */
                  /*  mov.l   r3,@r0                                          */
  0x63267004,     /*  add     #4,r0                                           */
                  /*  mov.l   @r2+,r3                        ! arg5           */
  0x70042032,     /*  mov.l   r3,@r0                                          */
                  /*  add     #4,r0                                           */
  0x20326326,     /*  mov.l   @r2+,r3                        ! arg6           */
                  /*  mov.l   r3,@r0                                          */
  0x63267004,     /*  add     #4,r0                                           */
                  /*  mov.l   @r2+,r3                        ! arg7           */
  0x70042032,     /*  mov.l   r3,@r0                                          */
                  /*  add     #4,r0                                           */
  0xe134e001,     /*  mov     #1,r0                          ! invoke prehandl*/
                  /*  mov     #state_off,r1                                   */
  0x2102318c,     /*  add     r8,r1                                           */
                  /*  mov.l   r0,@r1                         ! state          */
  0x0009bf7a,     /*  bsr     dorequest                                       */
                  /*  nop                                                     */
  0x308ce03c,     /*  mov     #res_off,r0                                     */
                  /*  add     r8,r0                                           */
  0x20086002,     /*  mov.l   @r0,r0                         ! res            */
                  /*  tst     r0,r0                                           */
  0x00098916,     /*  bt      skiporiginal                                    */
                  /*  nop                                                     */
  0x61e36093,     /*  mov     r9,r0                          ! load regs      */
                  /*  mov     r14,r1                         ! stack frame for*/
  0x65066406,     /*  mov.l   @r0+,r4                                         */
                  /*  mov.l   @r0+,r5                                         */
  0x67066606,     /*  mov.l   @r0+,r6                                         */
                  /*  mov.l   @r0+,r7                                         */
  0x21226206,     /*  mov.l   @r0+,r2                        ! load arg4      */
                  /*  mov.l   r2,@r1                                          */
  0x62067104,     /*  add     #4,r1                                           */
                  /*  mov.l   @r0+,r2                        ! load arg5      */
  0x71042122,     /*  mov.l   r2,@r1                                          */
                  /*  add     #4,r1                                           */
  0x21226206,     /*  mov.l   @r0+,r2                        ! load arg6      */
                  /*  mov.l   r2,@r1                                          */
  0x62067104,     /*  add     #4,r1                                           */
                  /*  mov.l   @r0+,r2                        ! load arg7      */
  0x71042122,     /*  mov.l   r2,@r1                                          */
                  /*  add     #4,r1                                           */
  0x400b5084,     /*  mov.l   @(orghandler_off,r8),r0                         */
                  /*  jsr     @r0                                             */
  0x29020009,     /*  nop                                                     */
                  /*  mov.l   r0,@r9                                          */
  0xe134e002,     /*  mov     #2,r0                          ! invoke posthand*/
                  /*  mov     #state_off,r1                                   */
  0x2102318c,     /*  add     r8,r1                                           */
                  /*  mov.l   r0,@r1                         ! state          */
  0x0009bf58,     /*  bsr     dorequest                                       */
                  /*  nop                                                     */
  0x2f066092,     /*  mov.l   @r9,r0                                          */
                  /*  mov.l   r0, @-r15                                       */
  0x64935082,     /*  mov.l   @(free_off,r8),r0              ! free           */
                  /*  mov     r9,r4                                           */
  0x0009400b,     /*  jsr     @r0                                             */
                  /*  nop                                                     */
  0xe414508a,     /*  mov.l   @(mutex_unlock_off,r8),r0      ! mutex_unlock   */
                  /*  mov     #gmutex_off,r4                                  */
  0x6442348c,     /*  add     r8,r4                                           */
                  /*  mov.l   @r4,r4                         ! mutex          */
  0x0009400b,     /*  jsr     @r0                                             */
                  /*  nop                                                     */
  0x6fe360f6,     /*  mov.l   @r15+, r0                                       */
                  /*  mov     r14, r15                                        */
  0x6df67f14,     /*  add     #20, r15                                        */
                  /*  mov.l   @r15+, r13                                      */
  0x6bf66cf6,     /*  mov.l   @r15+, r12                                      */
                  /*  mov.l   @r15+, r11                                      */
  0x69f66af6,     /*  mov.l   @r15+, r10                                      */
                  /*  mov.l   @r15+, r9                                       */
  0x67f668f6,     /*  mov.l   @r15+, r8                                       */
                  /*  mov.l   @r15+, r7                                       */
  0x65f666f6,     /*  mov.l   @r15+, r6                                       */
                  /*  mov.l   @r15+, r5                                       */
  0x63f664f6,     /*  mov.l   @r15+, r4                                       */
                  /*  mov.l   @r15+, r3                                       */
  0x61f662f6,     /*  mov.l   @r15+, r2                                       */
                  /*  mov.l   @r15+, r1                                       */
  0x4f2661f6,     /*  mov.l   @r15+, r1                                       */
                  /*  lds.l   @r15+, pr                                       */
  0x6ef6000b,     /*  rts                                                     */
                  /*  mov.l   @r15+, r14                                      */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
  0x00090009,     /*  nop                                                     */
                  /*  nop                                                     */
 };

 private static Hashtable handlers;
 private static int nextid;
 private static NativeCode nc;
 private static Logger l;
 private static ThreadGroup tg;

 private static int pthread_mutex_init;
 private static int pthread_mutex_lock;
 private static int pthread_mutex_unlock;

 private static int pthread_cond_init;
 private static int pthread_cond_wait;
 private static int pthread_cond_signal;

 public static final int PRE_HANDLER         = 1;
 public static final int POST_HANDLER        = 2;

 public static final int MAXARG              = 8;

 public static final int SIZEOF_MUTEX        = 24;
 public static final int SIZEOF_COND         = 48;

 public static final String RANDOM_PTHREAD_SYMBOL = "pthread_mutex_init";

 public static class HelperThread extends Thread {
  int ptr;

  public HelperThread(int code) {
   super(tg,"API handler");
   ptr=code+5*4;
  }

  public void run() {
   try {  
    int mutex=Memory.read_dword(ptr+0x14);
    int req=Memory.read_dword(ptr+0x18);
    int resp=Memory.read_dword(ptr+0x1c);

    while(true) {
     mutex_lock(mutex);

     while(true) {
      int preq=Memory.read_dword(ptr+0x3c);
      if (preq==0) cond_wait(req,mutex);
       else break;
     }

     /* set pending response flag */
     Memory.write_dword(ptr+0x3c,0);

     int monid=Memory.read_dword(ptr+0x08);
     int state=Memory.read_dword(ptr+0x30);
     int regs=Memory.read_dword(ptr+0x34);

     int res=handler(monid,state,regs);

     /* save API result           */
     Memory.write_dword(ptr+0x38,res);

     /* set pending response flag */
     Memory.write_dword(ptr+0x40,1);

     cond_signal(resp);

     mutex_unlock(mutex);
 
     if (false) break;
    }
   } catch(Throwable t) {}
  }

 }

 static {
  handlers=new Hashtable();
  nextid=1;
  nc=NativeCode.getInstance();

  int pid=CVM.attachProcess(-1);

  tg=new ThreadGroup(get_root_grup(),"Handler Group");
  tg.setDaemon(true);

  CVM.detachProcess(pid);

  if (Config.isHERMES()) {
   int pthread_base=ELFUtils.lib_base(RANDOM_PTHREAD_SYMBOL);  

   ELFUtils eu=new ELFUtils(pthread_base);

   pthread_mutex_init=eu.get_sym_addr("pthread_mutex_init");
   pthread_mutex_lock=eu.get_sym_addr("pthread_mutex_lock");
   pthread_mutex_unlock=eu.get_sym_addr("pthread_mutex_unlock");

   pthread_cond_init=eu.get_sym_addr("pthread_cond_init");
   pthread_cond_wait=eu.get_sym_addr("pthread_cond_wait");
   pthread_cond_signal=eu.get_sym_addr("pthread_cond_signal");
  } else

  if (Config.isCARBO()) {
   int handle=Dl.open_flags("libpthread-2.6.1.so",Dl.RTLD_NOW|Dl.RTLD_NODELETE);

   pthread_mutex_init=Dl.getsym(handle,"pthread_mutex_init");
   pthread_mutex_lock=Dl.getsym(handle,"pthread_mutex_lock");
   pthread_mutex_unlock=Dl.getsym(handle,"pthread_mutex_unlock");

   pthread_cond_init=Dl.getsym(handle,"pthread_cond_init");
   pthread_cond_wait=Dl.getsym(handle,"pthread_cond_wait");
   pthread_cond_signal=Dl.getsym(handle,"pthread_cond_signal");
  }
 }

 private static ThreadGroup get_root_grup() {
  ThreadGroup group=Thread.currentThread().getThreadGroup();

  while(group.getParent()!=null) {
   group=group.getParent();
  }
  
  return group;
 }

 public static synchronized void log(String s) {
  try {
   if (l==null) {
    l=new Logger();
   }
   l.log(s);
  } catch(Throwable t) {}
 }

 public static synchronized void log_stacktrace(Throwable th) {
  try {
   if (l==null) {
    l=new Logger();
   }

   StringWriter sw=new StringWriter();
   PrintWriter pw=new PrintWriter(sw);
   th.printStackTrace(pw);

   l.log("Exception: "+th);
   l.log(sw.toString());
  } catch(Throwable t) {}
 }

 public static synchronized void log_buf(byte[] buf) {
  try {
   if (l==null) {
    l=new Logger();
   }
   l.log_buf(buf);
  } catch(Throwable t) {}
 }

 public static synchronized void log_buf_as_line(byte[] buf) {
  try {
   if (l==null) {
    l=new Logger();
   }

   String s="";

   for(int i=0;i<buf.length;i++) {
    s+=" "+Utils.hex_value(((int)buf[i])&0xff,2);
   }
      
   l.log_buf(buf);
   l.log(s);
  } catch(Throwable t) {}
 }

 public static synchronized void dump_mem(String name,int addr) {
  try {
   if (l==null) {
    l=new Logger();
   }
   l.dump_mem(name,addr);
  } catch(Throwable t) {}
 }

 public static synchronized void dump_kmem_with_size(String name,int addr,int size) {
  try {
   if (l==null) {
    l=new Logger();
   }
   l.dump_kmem_with_size(name,addr,size);
  } catch(Throwable t) {}
 }

 public static synchronized void dump_iomem_with_size(String name,int addr,int size) {
  try {
   if (l==null) {
    l=new Logger();
   }
   l.dump_iomem_with_size(name,addr,size);
  } catch(Throwable t) {}
 }

 public static synchronized void dump_file_with_size(String name,int size) {
  try {
   if (l==null) {
    l=new Logger();
   }
   l.dump_file_with_size(name,size);
  } catch(Throwable t) {}
 }

 private static void mutex_init(int mutex) {
  NativeCode nc=NativeCode.getInstance();

  nc.invoke(pthread_mutex_init,mutex,0,0,0,0,0,0,0);
 }

 private static void mutex_lock(int mutex) {
  NativeCode nc=NativeCode.getInstance();

  nc.invoke(pthread_mutex_lock,mutex,0,0,0,0,0,0,0);
 }

 private static void mutex_unlock(int mutex) {
  NativeCode nc=NativeCode.getInstance();

  nc.invoke(pthread_mutex_unlock,mutex,0,0,0,0,0,0,0);
 }

 private static void cond_init(int cond) {
  NativeCode nc=NativeCode.getInstance();

  nc.invoke(pthread_cond_init,cond,0,0,0,0,0,0,0);
 }

 private static int cond_wait(int cond,int mutex) {
  NativeCode nc=NativeCode.getInstance();

  return nc.invoke(pthread_cond_wait,cond,mutex,0,0,0,0,0,0);
 }

 private static int cond_signal(int cond) {
  NativeCode nc=NativeCode.getInstance();

  return nc.invoke(pthread_cond_signal,cond,0,0,0,0,0,0,0);
 }

 private static int mutex_create() {
  int mutex=nc.malloc(SIZEOF_MUTEX);
  mutex_init(mutex);

  return mutex;
 }

 private static int cond_create() {
  int cond=nc.malloc(SIZEOF_COND);
  cond_init(cond);

  return cond;
 }

 private static ApiHandler lookup_handler(String name) {
  Enumeration e=handlers.elements();

  while(e.hasMoreElements()) {
   ApiHandler handler=(ApiHandler)e.nextElement();
   if (handler.name().equals(name)) return handler;
  }

  return null;  
 }

 public static ApiHandler lookup_handler(int monid) {
  return (ApiHandler)handlers.get(new Integer(monid));
 }

 public static int[] get_args(int ptr) {
  int args[]=new int[MAXARG];
  
  for(int i=0;i<MAXARG;i++) {
   args[i]=Memory.read_dword(ptr+4*i);
  }

  return args;
 }

 public static int[] get_res(int ptr) {
  int res[]=new int[1];
  
  res[0]=Memory.read_dword(ptr);

  return res;
 }

 public static int handler(int monid,int state,int ptr) {
  int retcode=ApiHandler.INVOKE_ORIGINAL;

  try {
   ApiHandler handler=(ApiHandler)handlers.get(new Integer(monid));
 
   if (handler!=null) {
    if (state==PRE_HANDLER) {
     int args[]=get_args(ptr);
     handler.put_args(ptr,args);
     retcode=handler.pre_call(ptr,args);
    } else

    if (state==POST_HANDLER) {
     int args[]=(int[])handler.get_args(ptr);
     int res[]=get_res(ptr);
     handler.post_call(ptr,args,res);
     handler.del_args(ptr);
    }
   }

  } catch(Throwable t) {
   log("ApiMonitor::handler "+t);
  }

  return retcode;
 }

 private static int prepare_handler(int monid,int orghandler) {
  int code=Utils.code2buf(handler_code);
  int ptr=code+5*4;

  int malloc=nc.get_sym_addr("malloc");
  int free=nc.get_sym_addr("free");

  int gmutex=mutex_create();
  int mutex=mutex_create();
  int req=cond_create();
  int resp=cond_create();

  Memory.write_dword(ptr+0x00,malloc);
  Memory.write_dword(ptr+0x04,free);
  Memory.write_dword(ptr+0x08,monid);
  Memory.write_dword(ptr+0x0c,orghandler);
  Memory.write_dword(ptr+0x10,gmutex);
  Memory.write_dword(ptr+0x14,mutex);
  Memory.write_dword(ptr+0x18,req);
  Memory.write_dword(ptr+0x1c,resp);
  Memory.write_dword(ptr+0x20,pthread_mutex_lock);
  Memory.write_dword(ptr+0x24,pthread_mutex_unlock);
  Memory.write_dword(ptr+0x28,pthread_cond_wait);
  Memory.write_dword(ptr+0x2c,pthread_cond_signal);
  
  int pid=CVM.attachProcess(-1);

  new HelperThread(code).start();

  CVM.detachProcess(pid);

  return code;
 }

 private static int register_handler_internal(String name,String function,int got_entry,String handlerclass) {
  int res=-1;

  ApiHandler handler=(ApiHandler)lookup_handler(name);

  if (handler==null) {
   try {
    Class c=Class.forName(handlerclass);

    if (function!=null) {
     got_entry=nc.get_got_addr(function);
     if (got_entry==0) return res;
    } else {
     if (got_entry==0) return res;
     function="0x"+Utils.hex_value(got_entry,8);
    }

    int orghandler=Memory.read_dword(got_entry);

    int monid=nextid++;
    int newcode=prepare_handler(monid,orghandler);

    Class ctab[]=new Class[4];
    ctab[0]=Class.forName("java.lang.String");
    ctab[1]=Class.forName("java.lang.String");
    ctab[2]=Integer.TYPE;
    ctab[3]=Integer.TYPE;

    Constructor con=c.getConstructor(ctab);
    
    Object otab[]=new Object[4];
    otab[0]=name;
    otab[1]=function;
    otab[2]=new Integer(monid);
    otab[3]=new Integer(newcode);

    handler=(ApiHandler)con.newInstance(otab);
    handler.set_orghandler(orghandler);

    handlers.put(new Integer(monid),handler);

    Memory.write_dword(got_entry,newcode);

    res=monid;
   } catch(Throwable t) {
    log("ApiMonitor::register_handler "+t);
   }
  }

  return res;
 }

 private static int register_handler(String name,String function,String handlerclass) {
  return register_handler_internal(name,function,0,handlerclass);
 }

 private static int register_handler(String name,int phandler,String handlerclass) {
  return register_handler_internal(name,null,phandler,handlerclass);
 }

 public static int add(String name,String function,String handlerclass) {
  return register_handler(name,function,handlerclass);  
 }

 public static int add(String name,int phandler,String handlerclass) {
  return register_handler(name,phandler,handlerclass);  
 }
}
