Integrating with ml64.exe

I’m back to Windows.
First, I started with writing simple functions in 32 and 64bit assembly. Visual Studio compiler supports 32bit inline assembly, but doesn’t support 64bit. Today, I used ml.exe/ml64.exe for both.

Here is the caller in C.

// asm.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#ifdef __cplusplus
extern "C" {
#endif
  char* _message();
  int _add(int a, int b);
  int _sub(int a, int b);
  int _fib(int a);
#ifdef __cplusplus
}
#endif

int _tmain(int argc, _TCHAR* argv[])
{
  int a = 10;
  int b = 20;

  printf("* started\n");
  int result = _add(a, b);

  printf("%d+%d=%d\n", a, b, result);
  result = _sub(a, b);
  printf("%d-%d=%d\n", a, b, result);

  for (int i = 0; i < 20; i++){
    result = _fib(i);
    printf("fib(%d)=%d\n", i, result);
  }
  printf("%s\n", _message());

  printf("* done\n");
  return 0;
}

That calls these.
asm64.asm:

.data
MSG	DB  "Hoge x64,", 0dh, 0ah, "Page!", 0dh, 0ah, 0

.code
; char* _message()
_message PROC
	mov rax, offset MSG
	ret
_message ENDP

; int _add(int a, int b)
_add PROC
add rcx, rdx			
mov rax, rcx
ret
_add ENDP

; int _sub(int a, int b)
_sub PROC
sub rcx, rdx			
mov rax, rcx
ret
_sub ENDP

; int _fib(int a)
_fib PROC
	cmp rcx, 0
	jz @ret0
	cmp rcx, 1
	jz @ret1

	push r12
	push r13

	mov r12, rcx
	sub r12, 1
	mov rcx, r12
	call _fib
	mov r13, rax

	sub r12, 1h
	mov rcx, r12
	call _fib
	add r13, rax

	mov rax, r13
	pop r13
	pop r12
	ret
@ret0:
	mov rax, 0
ret
@ret1:
	mov rax, 1
ret
_fib ENDP

END

asm32.asm:

.data
MSG	DB  "Hoge x64,", 0dh, 0ah, "Page!", 0dh, 0ah, 0

.code
; char* _message()
_message PROC
	mov rax, offset MSG
	ret
_message ENDP

; int _add(int a, int b)
_add PROC
add rcx, rdx			
mov rax, rcx
ret
_add ENDP

; int _sub(int a, int b)
_sub PROC
sub rcx, rdx			
mov rax, rcx
ret
_sub ENDP

; int _fib(int a)
_fib PROC
	cmp rcx, 0
	jz @ret0
	cmp rcx, 1
	jz @ret1

	push r12
	push r13

	mov r12, rcx
	sub r12, 1
	mov rcx, r12
	call _fib
	mov r13, rax

	sub r12, 1h
	mov rcx, r12
	call _fib
	add r13, rax

	mov rax, r13
	pop r13
	pop r12
	ret
@ret0:
	mov rax, 0
ret
@ret1:
	mov rax, 1
ret
_fib ENDP

END

Configure vcproj to run ml/ml64 using "custom build as below".
asm64_config

64 bit result:

C:\Users\sokoide\Projects\Spike\x64\Debug\asm.exe
* started
10+20=30
10-20=-10
fib(0)=0
fib(1)=1
fib(2)=1
fib(3)=2
fib(4)=3
fib(5)=5
fib(6)=8
fib(7)=13
fib(8)=21
fib(9)=34
fib(10)=55
fib(11)=89
fib(12)=144
fib(13)=233
fib(14)=377
fib(15)=610
fib(16)=987
fib(17)=1597
fib(18)=2584
fib(19)=4181
Hoge x64,
Page!

* done

32 bit result:

>C:\Users\sokoide\Projects\Spike\Debug\asm.exe
* started
10+20=30
10-20=-10
fib(0)=0
fib(1)=1
fib(2)=1
fib(3)=2
fib(4)=3
fib(5)=5
fib(6)=8
fib(7)=13
fib(8)=21
fib(9)=34
fib(10)=55
fib(11)=89
fib(12)=144
fib(13)=233
fib(14)=377
fib(15)=610
fib(16)=987
fib(17)=1597
fib(18)=2584
fib(19)=4181
Hoge x86,
Page!

* done

How to get .Net function parameters from crash dump

When debugging a crashed application from a crash dump, you often see that arguments to functions in the call stack are no data. Let’s say you want to get arguments for Hoge.Program.Test(Hoge.Foo, Hoge.Bar).
Since x64 calling convention use rcx/rdx/r8/r9 for the first 4 arguments, it’s not automatically pushed to the stack before the function call. However, sometimes the copy is stored in stack as below.

Exception:

0:000> !pe
Exception object: 000000e1000068e0
Exception type:   System.Exception
Message:          dummy exception
InnerException:   <none>
StackTrace (generated):
    SP               IP               Function
    000000E17AADEF00 00007FFB516702BC Hoge!Hoge.Program.TestSub()+0x3c
    000000E17AADEF40 00007FFB51670243 Hoge!Hoge.Program.Test(Hoge.Foo, Hoge.Bar)+0x123
    000000E17AADEFB0 00007FFB516700FE Hoge!Hoge.Program.Main(System.String[])+0x6e

StackTraceString: <none>
HResult: 80131500

Callstack:

0:000> !clrstack
OS Thread Id: 0x1bd4 (0)
        Child SP               IP Call Site
000000e17aadee18 00007ffbc0718b9c [HelperMethodFrame: 000000e17aadee18] 
000000e17aadef00 00007ffb516702bc Hoge.Program.TestSub() [c:\Users\sokoide\Projects\Spike\Hoge\Program.cs @ 45]
000000e17aadef40 00007ffb51670243 Hoge.Program.Test(Hoge.Foo, Hoge.Bar) [c:\Users\sokoide\Projects\Spike\Hoge\Program.cs @ 40]
000000e17aadefb0 00007ffb516700fe Hoge.Program.Main(System.String[]) [c:\Users\sokoide\Projects\Spike\Hoge\Program.cs @ 29]
000000e17aadf2d0 00007ffbb0caa7f3 [GCFrame: 000000e17aadf2d0] 


0:000> !clrstack -a
OS Thread Id: 0x1bd4 (0)
        Child SP               IP Call Site
000000e17aadee18 00007ffbc0718b9c [HelperMethodFrame: 000000e17aadee18] 
000000e17aadef00 00007ffb516702bc Hoge.Program.TestSub() [c:\Users\sokoide\Projects\Spike\Hoge\Program.cs @ 45]
    PARAMETERS:
        this = <no data>

000000e17aadef40 00007ffb51670243 Hoge.Program.Test(Hoge.Foo, Hoge.Bar) [c:\Users\sokoide\Projects\Spike\Hoge\Program.cs @ 40]
    PARAMETERS:
        this = <no data>
        foo = <no data>
        bar = <no data>
    LOCALS:
        <no data>

000000e17aadefb0 00007ffb516700fe Hoge.Program.Main(System.String[]) [c:\Users\sokoide\Projects\Spike\Hoge\Program.cs @ 29]
    PARAMETERS:
        args = <no data>

If you see the JIT compiled code for Hoge.Program.Test(Hoge.Foo, Hoge.Bar), you can confirm that rcx is copied in rbi, and the rbi is pushed into the stack at 00007ffb`51670123.

0:000> !U 00007ffb51670243 
Normal JIT generated code
Hoge.Program.Test(Hoge.Foo, Hoge.Bar)
Begin 00007ffb51670120, size 131

c:\Users\sokoide\Projects\Spike\Hoge\Program.cs @ 34:
00007ffb`51670120 53              push    rbx
00007ffb`51670121 55              push    rbp
00007ffb`51670122 56              push    rsi
00007ffb`51670123 57              push    rdi
00007ffb`51670124 4154            push    r12
00007ffb`51670126 4155            push    r13
00007ffb`51670128 4883ec38        sub     rsp,38h
00007ffb`5167012c 498be8          mov     rbp,r8
00007ffb`5167012f 488bfa          mov     rdi,rdx
00007ffb`51670132 488bf1          mov     rsi,rcx
00007ffb`51670135 33db            xor     ebx,ebx
00007ffb`51670137 bab0000000      mov     edx,0B0h
00007ffb`5167013c b901000000      mov     ecx,1

If you can get stack base address when Test(Hoge.Foo, Hoge.Bar) is called, you can get those copied registers which have the Hoge.Foo/Bar arguments.
Since child-sp when the Test function is called is 000000E17AADEFB0, 000000E17AADEFB0-0x8 is the ret address, and 000000E17AADEFB0-0x10 is the base address as below. Then you can get rcx (this), rdx (1st arg), r8 (2nd arg) stored in rsi(<-rcx), rdi(<-rdx), rbp(<-r8) respectively.

0:000> dq 000000e1`7aadef40 000000e1`7aadefff
[7aadef40 – 7aadef78] = 0x38 … local vars
000000e1`7aadef40  000000e1`00002d38 00000000`00000000
000000e1`7aadef50  000000e1`00005b0c 00000000`00000000
000000e1`7aadef60  000000e1`00000009 000000e1`00002d38
000000e1`7aadef70  000000e1`00002d68 000000e1`7aadf300 (r13)
000000e1`7aadef80  000000e1`7aadf348(r12) 000000e1`00002d50 (rdi)
000000e1`7aadef90  000000e1`00002d38(rsi) 000000e1`7aadf010 (rbp)
000000e1`7aadefa0  000000e1`00002d68(rbx) 00007ffb`516700fe (ret)
000000e1`7aadefb0  000000e1`00002d38(child-sp) 000000e1`00002d50
000000e1`7aadefc0  000000e1`00002d68 000000e1`00000001
000000e1`7aadefd0  000000e1`7aadf2d0 000000e1`7aadf128
000000e1`7aadefe0  000000e1`7aadf1a0 00007ffb`b0caa7f3
000000e1`7aadeff0  000000e1`00002cc8 000000e1`7aadf500

this = rcx)
0:000> !do 000000e1`00002d38
Name:        Hoge.Program
MethodTable: 00007ffb51554038
EEClass:     00007ffb516624a8
Size:        24(0x18) bytes
File:        C:\Users\sokoide\Projects\Spike\Hoge\bin\Release\Hoge.exe
Fields:
None

1st arg = rdx)
0:000> !do 000000e1`00002d50
Name:        Hoge.Foo
MethodTable: 00007ffb51554120
EEClass:     00007ffb51662520
Size:        24(0x18) bytes
File:        C:\Users\sokoide\Projects\Spike\Hoge\bin\Release\Hoge.exe
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffbafad0e08  4000012        8        System.String  0 instance 000000e100002ce8 <Name>k__BackingField

2nd arg = r8)
0:000> !do 000000e1`7aadf010
<Note: this object has an invalid CLASS field>
Invalid object

… looks the pointer doesn’t have the class info. However, we know the type is Hoge.Bar!
0:000> !dumpheap -type Bar
         Address               MT     Size
000000e100002d68 00007ffb51554208       24     

Statistics:
              MT    Count    TotalSize Class Name
00007ffb51554208        1           24 Hoge.Bar
Total 1 objects

then we can get the object detail using !dumpvc and the method table and the object pointer as below.
0:000> !dumpvc 00007ffb51554208 000000e1`7aadf010
Name:        Hoge.Bar
MethodTable: 00007ffb51554208
EEClass:     00007ffb51662598
Size:        24(0x18) bytes
File:        C:\Users\sokoide\Projects\Spike\Hoge\bin\Release\Hoge.exe
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffbafad0e08  4000013        0        System.String  0 instance 000000e17aadf150 <Name>k__BackingField

Here is the target application which was used to demonstrate it.

class Foo
{
    public string Name { get; set; }
}

class Bar
{
    public string Name { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();

        Foo foo = new Foo { Name = "hoge" };
        Bar bar = new Bar { Name = "page" };
        p.Test(foo, bar);
    }

    private void Test(Foo foo, Bar bar)
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("Hello {0}", i);
        }
        Console.WriteLine(foo.Name);
        Console.WriteLine(bar.Name);
        TestSub();
    }

    private void TestSub()
    {
        throw new Exception("dummy exception");
    }
}

x86_64 calling convention

As written in Wikipedia, Linux/MacOS X uses RDI, RSI, RDX, RCX, R8, and R9 for the first 6 args (uses XMM0-7 fro float) + stack for the others.

Windows uses RCX, RDX, R8, R9 (uses XMM0-3 for float) + stack.

#include <iostream>

using namespace std;

int foo(int a, int b, int c, int d, int e, int f, int g){
  int r = a+b+c+d+e+f+g;
  return r;
}

int main(int argc, char const* argv[])
{
  cout << foo(1,2,3,4,5,6,7);
  return 0;
}

MacOS X 10.9:

(lldb) disassemble --name main
foo`main:
foo[0x100000ec0]:  push   rbp
foo[0x100000ec1]:  mov    rbp, rsp
foo[0x100000ec4]:  push   rbx
foo[0x100000ec5]:  sub    rsp, 0x38
foo[0x100000ec9]:  mov    eax, 0x1
foo[0x100000ece]:  mov    ecx, 0x2
foo[0x100000ed3]:  mov    edx, 0x3
foo[0x100000ed8]:  mov    r8d, 0x4
foo[0x100000ede]:  mov    r9d, 0x5
foo[0x100000ee4]:  mov    r10d, 0x6
foo[0x100000eea]:  mov    r11d, 0x7
foo[0x100000ef0]:  mov    rbx, qword ptr [rip + 0x121] ; (void *)0x0000000000000000
foo[0x100000ef7]:  mov    rbx, qword ptr [rbx]
foo[0x100000efa]:  mov    qword ptr [rbp - 0x10], rbx
foo[0x100000efe]:  mov    dword ptr [rbp - 0x14], 0x0
foo[0x100000f05]:  mov    dword ptr [rbp - 0x18], edi
foo[0x100000f08]:  mov    qword ptr [rbp - 0x20], rsi
foo[0x100000f0c]:  mov    edi, eax
foo[0x100000f0e]:  mov    esi, ecx
foo[0x100000f10]:  mov    ecx, r8d
foo[0x100000f13]:  mov    r8d, r9d
foo[0x100000f16]:  mov    r9d, r10d
foo[0x100000f19]:  mov    dword ptr [rsp], 0x7
foo[0x100000f20]:  mov    dword ptr [rbp - 0x24], r11d
foo[0x100000f24]:  call   0x100000e50               ; foo(int, int, int, int, int, int, int)
foo[0x100000f29]:  mov    rdi, qword ptr [rip + 0xe0] ; (void *)0x0000000000000000
foo[0x100000f30]:  mov    esi, eax
foo[0x100000f32]:  call   0x100000f60               ; symbol stub for: std::__1::basic_ostream<char, std::__1::char_traits<char> >::operator<<(int)
foo[0x100000f37]:  mov    rdi, qword ptr [rip + 0xda] ; (void *)0x0000000000000000
foo[0x100000f3e]:  mov    rdi, qword ptr [rdi]
foo[0x100000f41]:  cmp    rdi, qword ptr [rbp - 0x10]
foo[0x100000f45]:  mov    qword ptr [rbp - 0x30], rax
foo[0x100000f49]:  jne    0x100000f5b               ; main + 155
foo[0x100000f4f]:  mov    eax, 0x0
foo[0x100000f54]:  add    rsp, 0x38
foo[0x100000f58]:  pop    rbx
foo[0x100000f59]:  pop    rbp
foo[0x100000f5a]:  ret    
foo[0x100000f5b]:  call   0x100000f66               ; symbol stub for: __stack_chk_fail
 
(lldb) disassemble --name foo
foo`foo(int, int, int, int, int, int, int):
foo[0x100000e50]:  push   rbp
foo[0x100000e51]:  mov    rbp, rsp
foo[0x100000e54]:  sub    rsp, 0x30
foo[0x100000e58]:  mov    eax, dword ptr [rbp + 0x10]
foo[0x100000e5b]:  mov    r10, qword ptr [rip + 0x1b6] ; (void *)0x0000000000000000
foo[0x100000e62]:  mov    r11, qword ptr [r10]
foo[0x100000e65]:  mov    qword ptr [rbp - 0x8], r11
foo[0x100000e69]:  mov    dword ptr [rbp - 0xc], edi
foo[0x100000e6c]:  mov    dword ptr [rbp - 0x10], esi
foo[0x100000e6f]:  mov    dword ptr [rbp - 0x14], edx
foo[0x100000e72]:  mov    dword ptr [rbp - 0x18], ecx
foo[0x100000e75]:  mov    dword ptr [rbp - 0x1c], r8d
foo[0x100000e79]:  mov    dword ptr [rbp - 0x20], r9d
foo[0x100000e7d]:  mov    dword ptr [rbp - 0x24], eax
foo[0x100000e80]:  mov    eax, dword ptr [rbp - 0xc]
foo[0x100000e83]:  add    eax, dword ptr [rbp - 0x10]
foo[0x100000e86]:  add    eax, dword ptr [rbp - 0x14]
foo[0x100000e89]:  add    eax, dword ptr [rbp - 0x18]
foo[0x100000e8c]:  add    eax, dword ptr [rbp - 0x1c]
foo[0x100000e8f]:  add    eax, dword ptr [rbp - 0x20]
foo[0x100000e92]:  add    eax, dword ptr [rbp - 0x24]
foo[0x100000e95]:  mov    dword ptr [rbp - 0x28], eax
foo[0x100000e98]:  mov    eax, dword ptr [rbp - 0x28]
foo[0x100000e9b]:  mov    r10, qword ptr [r10]
foo[0x100000e9e]:  cmp    r10, qword ptr [rbp - 0x8]
foo[0x100000ea2]:  mov    dword ptr [rbp - 0x2c], eax
foo[0x100000ea5]:  jne    0x100000eb4               ; foo(int, int, int, int, int, int, int) + 100
foo[0x100000eab]:  mov    eax, dword ptr [rbp - 0x2c]
foo[0x100000eae]:  add    rsp, 0x30
foo[0x100000eb2]:  pop    rbp
foo[0x100000eb3]:  ret    
foo[0x100000eb4]:  call   0x100000f66               ; symbol stub for: __stack_chk_fail
foo[0x100000eb9]:  nop    dword ptr [rax]

Windows 8:

0:000> uf foo!main (int, char **)
foo!main [c:\users\sokoide\projects\spike\foo\foo.cpp @ 16]:
   16 00007ff7`fbfd2400 4889542410      mov     qword ptr [rsp+10h],rdx
   16 00007ff7`fbfd2405 894c2408        mov     dword ptr [rsp+8],ecx
   16 00007ff7`fbfd2409 57              push    rdi
   16 00007ff7`fbfd240a 4883ec40        sub     rsp,40h
   16 00007ff7`fbfd240e 488bfc          mov     rdi,rsp
   16 00007ff7`fbfd2411 b910000000      mov     ecx,10h
   16 00007ff7`fbfd2416 b8cccccccc      mov     eax,0CCCCCCCCh
   16 00007ff7`fbfd241b f3ab            rep stos dword ptr [rdi]
   16 00007ff7`fbfd241d 8b4c2450        mov     ecx,dword ptr [rsp+50h]
   17 00007ff7`fbfd2421 c744243007000000 mov     dword ptr [rsp+30h],7
   17 00007ff7`fbfd2429 c744242806000000 mov     dword ptr [rsp+28h],6
   17 00007ff7`fbfd2431 c744242005000000 mov     dword ptr [rsp+20h],5
   17 00007ff7`fbfd2439 41b904000000    mov     r9d,4
   17 00007ff7`fbfd243f 41b803000000    mov     r8d,3
   17 00007ff7`fbfd2445 ba02000000      mov     edx,2
   17 00007ff7`fbfd244a b901000000      mov     ecx,1
   17 00007ff7`fbfd244f e8f6ecffff      call    foo!ILT+325(?fooYAHHHHHHHHZ) (00007ff7`fbfd114a)
   17 00007ff7`fbfd2454 8bd0            mov     edx,eax
   17 00007ff7`fbfd2456 488b0dc3ec0000  mov     rcx,qword ptr [foo!_imp_?coutstd (00007ff7`fbfe1120)]
   17 00007ff7`fbfd245d ff15c5ec0000    call    qword ptr [foo!_imp_??6?$basic_ostreamDU?$char_traitsDstdstdQEAAAEAV01HZ (00007ff7`fbfe1128)]
   18 00007ff7`fbfd2463 33c0            xor     eax,eax
   19 00007ff7`fbfd2465 4883c440        add     rsp,40h
   19 00007ff7`fbfd2469 5f              pop     rdi
   19 00007ff7`fbfd246a c3              ret
                   ^ Extra character error in 'uf foo!main (int, char **)'
0:000> uf foo!foo (int, int, int, int, int, int, int)
foo!foo [c:\users\sokoide\projects\spike\foo\foo.cpp @ 10]:
   10 00007ff7`fbfd23a0 44894c2420      mov     dword ptr [rsp+20h],r9d
   10 00007ff7`fbfd23a5 4489442418      mov     dword ptr [rsp+18h],r8d
   10 00007ff7`fbfd23aa 89542410        mov     dword ptr [rsp+10h],edx
   10 00007ff7`fbfd23ae 894c2408        mov     dword ptr [rsp+8],ecx
   10 00007ff7`fbfd23b2 57              push    rdi
   10 00007ff7`fbfd23b3 4883ec10        sub     rsp,10h
   10 00007ff7`fbfd23b7 488bfc          mov     rdi,rsp
   10 00007ff7`fbfd23ba b904000000      mov     ecx,4
   10 00007ff7`fbfd23bf b8cccccccc      mov     eax,0CCCCCCCCh
   10 00007ff7`fbfd23c4 f3ab            rep stos dword ptr [rdi]
   10 00007ff7`fbfd23c6 8b4c2420        mov     ecx,dword ptr [rsp+20h]
   11 00007ff7`fbfd23ca 8b442428        mov     eax,dword ptr [rsp+28h]
   11 00007ff7`fbfd23ce 8b4c2420        mov     ecx,dword ptr [rsp+20h]
   11 00007ff7`fbfd23d2 03c8            add     ecx,eax
   11 00007ff7`fbfd23d4 8bc1            mov     eax,ecx
   11 00007ff7`fbfd23d6 03442430        add     eax,dword ptr [rsp+30h]
   11 00007ff7`fbfd23da 03442438        add     eax,dword ptr [rsp+38h]
   11 00007ff7`fbfd23de 03442440        add     eax,dword ptr [rsp+40h]
   11 00007ff7`fbfd23e2 03442448        add     eax,dword ptr [rsp+48h]
   11 00007ff7`fbfd23e6 03442450        add     eax,dword ptr [rsp+50h]
   11 00007ff7`fbfd23ea 890424          mov     dword ptr [rsp],eax
   12 00007ff7`fbfd23ed 8b0424          mov     eax,dword ptr [rsp]
   13 00007ff7`fbfd23f0 4883c410        add     rsp,10h
   13 00007ff7`fbfd23f4 5f              pop     rdi
   13 00007ff7`fbfd23f5 c3              ret
                  ^ Extra character error in 'uf foo!foo (int, int, int, int, int, int, int)'

ETW test

Created a test php page which simply sleeps for a specified seconds, and called it from Windows with ETW turned on.

On Mac: test.php

<?php
$delay = $_GET["delay"];
sleep($delay);
echo date('h:i:s') . "<br/>\n";
?>

On Windows:

start:
xperf.exe -on PROC_THREAD+LOADER+Base+CSWITCH+DISPATCHER -stackwalk Profile+CSwitch+ReadyThread

run the test:
Open Powershell Window and run -
 $wc = New-Object System.Net.WebClient
 $wc.DownloadString("http://hogeaddress:hogeport/hogedirectory/test.php?delay=5")

stop:
xperf.exe -stop -d %temp%\hoge.etl

see the trace:
xperf.exe %temp%\hoge.etl

It traced in kernel mode when the user mode thread waited on the sync object.
ETW

Import Lookup Table

Came back to Windows world and played with windbg.

The following code showed f1096 as a function pointer of ‘add’, but the final address was f13c0. Visual Studio compiler creates function address table ILT which makes relative jump to the actual functions.

CppGeneral.cpp:

#include "stdafx.h"

int add(int a, int b);

typedef int (*PTR_ADD)(int, int);

int add(int a, int b){
    return a+b;
}

int _tmain(int argc, _TCHAR* argv[])
{
    PTR_ADD pAdd = add;

    _tprintf(_T("%d\n"), add(3, 4));
    _tprintf(_T("%d, address=%x\n"), pAdd(3, 4), pAdd);

    getchar();
    return 0;
}

Output:

7
7, address = f1096

Debug log:

0:001> uf CppGeneral!wmain
CppGeneral!wmain [c:\users\sokoide\projects\general\cppgeneral\cppgeneral.cpp @ 15]:
   15 000f1a70 55              push    ebp
   15 000f1a71 8bec            mov     ebp,esp
   15 000f1a73 81eccc000000    sub     esp,0CCh
   15 000f1a79 53              push    ebx
   15 000f1a7a 56              push    esi
   15 000f1a7b 57              push    edi
   15 000f1a7c 8dbd34ffffff    lea     edi,[ebp-0CCh]
   15 000f1a82 b933000000      mov     ecx,33h
   15 000f1a87 b8cccccccc      mov     eax,0CCCCCCCCh
   15 000f1a8c f3ab            rep stos dword ptr es:[edi]
   16 000f1a8e c745f896100f00  mov     dword ptr [ebp-8],offset CppGeneral!ILT+145(?addYAHHHZ) (000f1096)
   18 000f1a95 6a04            push    4
   18 000f1a97 6a03            push    3
   18 000f1a99 e8f8f5ffff      call    CppGeneral!ILT+145(?addYAHHHZ) (000f1096)
   18 000f1a9e 83c408          add     esp,8
   18 000f1aa1 8bf4            mov     esi,esp
   18 000f1aa3 50              push    eax
   18 000f1aa4 683c570f00      push    offset CppGeneral!`string' (000f573c)
   18 000f1aa9 ff15d4820f00    call    dword ptr [CppGeneral!_imp__wprintf (000f82d4)]
   18 000f1aaf 83c408          add     esp,8
   18 000f1ab2 3bf4            cmp     esi,esp
   18 000f1ab4 e887f6ffff      call    CppGeneral!ILT+315(__RTC_CheckEsp) (000f1140)
   19 000f1ab9 8bf4            mov     esi,esp
   19 000f1abb 8b45f8          mov     eax,dword ptr [ebp-8]
   19 000f1abe 50              push    eax
   19 000f1abf 8bfc            mov     edi,esp
   19 000f1ac1 6a04            push    4
   19 000f1ac3 6a03            push    3
   19 000f1ac5 ff55f8          call    dword ptr [ebp-8]
   19 000f1ac8 83c408          add     esp,8
   19 000f1acb 3bfc            cmp     edi,esp
   19 000f1acd e86ef6ffff      call    CppGeneral!ILT+315(__RTC_CheckEsp) (000f1140)
   19 000f1ad2 50              push    eax
   19 000f1ad3 68e05a0f00      push    offset CppGeneral!`string' (000f5ae0)
   19 000f1ad8 ff15d4820f00    call    dword ptr [CppGeneral!_imp__wprintf (000f82d4)]
   19 000f1ade 83c40c          add     esp,0Ch
   19 000f1ae1 3bf4            cmp     esi,esp
   19 000f1ae3 e858f6ffff      call    CppGeneral!ILT+315(__RTC_CheckEsp) (000f1140)
   21 000f1ae8 8bf4            mov     esi,esp
   21 000f1aea ff15d8820f00    call    dword ptr [CppGeneral!_imp__getchar (000f82d8)]
   21 000f1af0 3bf4            cmp     esi,esp
   21 000f1af2 e849f6ffff      call    CppGeneral!ILT+315(__RTC_CheckEsp) (000f1140)
   22 000f1af7 33c0            xor     eax,eax
   23 000f1af9 5f              pop     edi
   23 000f1afa 5e              pop     esi
   23 000f1afb 5b              pop     ebx
   23 000f1afc 81c4cc000000    add     esp,0CCh
   23 000f1b02 3bec            cmp     ebp,esp
   23 000f1b04 e837f6ffff      call    CppGeneral!ILT+315(__RTC_CheckEsp) (000f1140)
   23 000f1b09 8be5            mov     esp,ebp
   23 000f1b0b 5d              pop     ebp
   23 000f1b0c c3              ret


0:001> X CppGeneral!a*
000f7144 CppGeneral!argv = 0x003a1480
000f713c CppGeneral!argc = 0n1
000f13c0 CppGeneral!add (int, int)             // <-- add is at f13c0
000f2880 CppGeneral!atexit (<function> *)


0:001> u f1096
CppGeneral!ILT+145(?addYAHHHZ):
000f1096 e925030000      jmp     CppGeneral!add (000f13c0)   // <-- f1096 is calling jmp to f13c0


(It seems ILT is stored here)
0:001> u f1004 f1100
CppGeneral!_enc$textbss$end <PERF> (CppGeneral+0x11004):
000f1004 cc              int     3
CppGeneral!ILT+0(__setdefaultprecision):
000f1005 e936160000      jmp     CppGeneral!_setdefaultprecision (000f2640)
CppGeneral!ILT+5(_wmain):
000f100a e9610a0000      jmp     CppGeneral!wmain (000f1a70)
...
000f1096 e925030000      jmp     CppGeneral!add (000f13c0)
CppGeneral!ILT+150(__exit):
000f109b e938190000      jmp     CppGeneral!exit (000f29d8)
...


(add starts at f13c0)
0:001> uf CppGeneral!add
CppGeneral!add [c:\users\sokoide\projects\general\cppgeneral\cppgeneral.cpp @ 10]:
   10 000f13c0 55              push    ebp
   10 000f13c1 8bec            mov     ebp,esp
   10 000f13c3 81ecc0000000    sub     esp,0C0h
   10 000f13c9 53              push    ebx
   10 000f13ca 56              push    esi
   10 000f13cb 57              push    edi
   10 000f13cc 8dbd40ffffff    lea     edi,[ebp-0C0h]
   10 000f13d2 b930000000      mov     ecx,30h
   10 000f13d7 b8cccccccc      mov     eax,0CCCCCCCCh
   10 000f13dc f3ab            rep stos dword ptr es:[edi]
   11 000f13de 8b4508          mov     eax,dword ptr [ebp+8]
   11 000f13e1 03450c          add     eax,dword ptr [ebp+0Ch]
   12 000f13e4 5f              pop     edi
   12 000f13e5 5e              pop     esi
   12 000f13e6 5b              pop     ebx
   12 000f13e7 8be5            mov     esp,ebp
   12 000f13e9 5d              pop     ebp
   12 000f13ea c3              ret

Zabbix Agent for Windows

Downloaded the latest Windows binary and ran it with windows config in the source tar file.

Defined server address – one for passive and the other for active monitoring. Then added perf counter and files.

Server=hogehoge
ServerActive=hogehoge

Created “Windows Eventlog” application to store event logs.

Successfully configured file monitor. Notice that no single or double quote supported!

 log[c:\users\sokoide\hoge.log]