I am currently working with an application trying to integrate BreakPad into a Qt application. I found a page that helped me out a bunch with the initial setup and quirks.
https://github.com/JPNaude/dev_notes/wiki/Using-Google-Breakpad-with-Qt
I still cannot get it to work for actual exceptions. I created a demo application and it is having the same issue. Here are the steps I am following to test. I am testing in debug right now.
Build the application Run dump_syms.exe BreakpadTest.pdb > BreakpadTest.sym
Run the application and generate a dump file
Run minidump_stackwalk dumpfile.dmp symbols > out.txt 2>&1
Check out.txt for the file path to place the BreakpadTest.sym
Move the BreakpadTest.sym file to the proper location
Run minidump_stackwalk dumpfile.dmp symbols > out.txt 2>&1 again
This leaves me with an out.txt file.
When I call dumpFunc in my demo application which executes this code
Breakpad::CrashHandler::instance()->writeMinidump();
I get the folowing output
Thread 0 (crashed)
0 BreakpadTest.exe!Breakpad::CrashHandler::writeMinidump() [crashhandler.cpp : 118 + 0xb]
eip = 0x00c03a44 esp = 0x00affe18 ebp = 0x00affe48 ebx = 0x009fe000
esi = 0x00c01960 edi = 0x00c01960 eax = 0x00affaf0 ecx = 0x00affaf0
edx = 0x00affdbc efl = 0x00000216
Found by: given as instruction pointer in context
1 BreakpadTest.exe!dumpFunc() [main.cpp : 13 + 0xb]
eip = 0x00c0364f esp = 0x00affe50 ebp = 0x00affe50
Found by: call frame info
2 BreakpadTest.exe!main [main.cpp : 25 + 0x4]
eip = 0x00c03746 esp = 0x00affe58 ebp = 0x00affea0
Found by: call frame info
3 BreakpadTest.exe!WinMain [qtmain_win.cpp : 113 + 0xc]
eip = 0x00c14d3d esp = 0x00affea8 ebp = 0x00affed4
Found by: call frame info
4 BreakpadTest.exe!invoke_main [exe_common.inl : 94 + 0x1a]
eip = 0x00c13b7e esp = 0x00affedc ebp = 0x00affeec
Found by: call frame info
5 BreakpadTest.exe!__scrt_common_main_seh [exe_common.inl : 253 + 0x4]
eip = 0x00c13a00 esp = 0x00affef4 ebp = 0x00afff44
Found by: call frame info
6 BreakpadTest.exe!__scrt_common_main [exe_common.inl : 295 + 0x4]
eip = 0x00c1389d esp = 0x00afff4c ebp = 0x00afff4c
Found by: call frame info
7 BreakpadTest.exe!WinMainCRTStartup [exe_winmain.cpp : 16 + 0x4]
eip = 0x00c13b98 esp = 0x00afff54 ebp = 0x00afff54
Found by: call frame info
8 kernel32.dll + 0x162c3
eip = 0x76c962c4 esp = 0x00afff5c ebp = 0x00afff68
Found by: call frame info
9 ntdll.dll + 0x60fd8
eip = 0x77850fd9 esp = 0x00afff70 ebp = 0x00afffb0
Found by: previous frame's frame pointer
10 ntdll.dll + 0x60fa3
eip = 0x77850fa4 esp = 0x00afffb8 ebp = 0x00afffc0
Found by: previous frame's frame pointer
This is good and what I want. But when I actually cause an exception with badFunc().
int *myNull = NULL;
*myNull = 42;
I get the following output
Thread 0 (crashed)
0 ntdll.dll + 0x6e5fc
eip = 0x7785e5fc esp = 0x00eff09c ebp = 0x00eff10c ebx = 0x00000001
esi = 0x00000000 edi = 0x00000368 eax = 0x00000000 ecx = 0x6d278097
edx = 0x00000000 efl = 0x00000206
Found by: given as instruction pointer in context
1 KERNELBASE.dll + 0xcad51
eip = 0x74d7ad52 esp = 0x00eff114 ebp = 0x00eff120
Found by: previous frame's frame pointer
2 BreakpadTest.exe!google_breakpad::ExceptionHandler::WriteMinidumpOnHandlerThread(_EXCEPTION_POINTERS *,MDRawAssertionInfo *) [exception_handler.cc : 720 + 0x11]
eip = 0x009f72d0 esp = 0x00eff128 ebp = 0x00eff138
Found by: previous frame's frame pointer
3 BreakpadTest.exe!google_breakpad::ExceptionHandler::HandleException(_EXCEPTION_POINTERS *) [exception_handler.cc : 504 + 0xd]
eip = 0x009f6d71 esp = 0x00eff140 ebp = 0x00eff178
Found by: call frame info
4 KERNELBASE.dll + 0x15d411
eip = 0x74e0d412 esp = 0x00eff180 ebp = 0x00eff20c
Found by: call frame info
5 ntdll.dll + 0x9e0bc
eip = 0x7788e0bd esp = 0x00eff214 ebp = 0x00effa10
Found by: previous frame's frame pointer
6 ntdll.dll + 0x60fa3
eip = 0x77850fa4 esp = 0x00effa18 ebp = 0x00effa20
Found by: previous frame's frame pointer
This is not the actual stack trace where the exception occurred. Any ideas on what is going wrong or how I can change it to get the actual stack?
Demo Application
http://s000.tinyupload.com/?file_id=26352983283926785193
I have been recently down the same rabbit hole as well. Taking resources from many places, I put together everything I found in this repo.
One of the things that might affect the stack output is if the optimization level that you are using to compile your application. It doesn't matter if you force the creation of debug symbols. The stack will sometimes appear incorrect if you apply any optimization, so what you can try is to disable optimization in your Qt project (*.pro file) for your release builds as follows:
CONFIG *= force_debug_info
QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO -= -O2
Related
The main application file is crashing becausing The server is affected by a format string bug when handles the players nicknames due the access to
an invalid memory zone.
The instruction executed is "cmp [EAX], 00000000" where EAX contains 4
of the bytes in the nickname and Crashes the Server.
I debugged and found that "%s" is missing before the logging string passed to the File_printf function. So i have tried to add this string via IDA Debugger and Successed. After entering these bytes now the server is crashing with the message "server is not vulnerable" before it was crashing with the message "server is vulnerable"
CODE
Bytes I have entered to patch the application:
RVA
00400000
OFFSET
0041dfad cc 68 ; push 0061d0dc
+ cc |0061d0dc
+ cc e8 ; call 0040d270
+ cc ^0040d270
+ cc 83 ; add esp,04
+ cc c4
+ cc 04
+ cc e9 ; jmp 0041e059
+ cc ^0041e059
0041e054 e8 e9 ; jmp 0041dfad
+ ?? ^0041dfad
0055DD63 cmp dword ptr [eax], 0
/*source*/
if ( *(_DWORD *)a1 )
a1 = sub_445D50();
if ( v2 )
{
--*(_DWORD *)(v2 + 4);
*(_DWORD *)a1 = *(_DWORD *)(v2 + 20);
*(_DWORD *)(v2 + 20) = a1;
}
else
{
v3 = *(_DWORD *)((a1 - 4) & 0xFFFFFFFC);
--dword_798ABD0;
sub_445D50();
memset(*(void **)(v3 + 8), 0xCDu, *(_DWORD *)(v3 + 16));
free((void *)v3);
}
}
/Hex Value/
0055DD63 83 38 00
After Testing the Server to Crash then the server Crashed with the message in the testing tool "Server is not Vulnerable" but Crashed.
And in the Debugger IDA i get this result with the detailed Message:
55dd63: The Instruction at 0x55DD63 referenced memory at 0x61616161, The memory could not be read -> 61616161 (exc.code c0000005, tid 4692)
Image 1
Image 2
Image 3
Image 4
Image 5
I can Share the testing tool also but not here because the testing tool has .simplese trojan and it may harm your pc, but i can share the Source code of the testing tool on Request.
The bug is caused by the logging function NetManager_LogMessage which
takes the text to dump, adds a timestamp (using snprintf) and then
passes the whole string to the function File_printf without the needed
format argument (%s) and you need to using the value 05 instead of 04 to make an ampty space to fool the bug. This trick work on many games and good luck
My problem is the following. I have a code unit composed of various c files, say for example
file1.c
file2.c
file3.c
that are all compiled with GCC to a unique object "object.o", which in turn is then linked with other objects to give at the end the executable "application.out", running on VxWorks.
Since I'm doing unit testing on "object.o", my need is to stimulate all the possible ways through the code. Specifically, there are situations where I should have mock functions executed instead of original ones in order to simulate error occurrences.
Suppose for example that there is a function "func_caller" that I'm trying to test that, at some point in the execution, makes a call to another function "func_called" (declared as static).
Since I DON'T WANT TO MODIFY THE ORIGINAL CODE, I wonder if there is a way to manipulate the instruction pointers in such a way that when "func_called" is called, it actually executes another mock function "func_called_mock" and the caller "func_caller" does not notice anything.
Thanks in advance.
The most direct method of overriding function calls would be to use VxWorks's load time linking. Consider the following source:
file1.c:
#include <stdio.h>
int function1 (void);
int function1 ()
{
printf ("function1 called\n");
return 1;
}
file2.c:
#include <stdio.h>
int function2 (void);
int function2 ()
{
printf ("function2 called\n");
return 2;
}
file3.c:
int function1 (void);
int function2 (void);
int function3 (void);
int function3 ()
{
function1 ();
function2 ();
return 0;
}
mock.c:
#include <stdio.h>
int function1 (void);
int function2 (void);
int function1 ()
{
printf ("mock function1 called\n");
return 1;
}
int function2 ()
{
printf ("mock function2 called\n");
return 2;
}
When you load an object, its functions are added to the global symbol table.
-> ld < file1.o
value = 273740816 = 0x1050f410
-> lkup "function"
function1 0x108b0000 text (file1.o)
value = 0 = 0x0
->
When you load an object that uses functions already in the symbol table, each call will be immediately resolved to the last address associated with that symbol in the table.
-> ld < file2.o
value = 292535232 = 0x116fbbc0
-> ld < file3.o
value = 292537592 = 0x116fc4f8
-> lkup "function"
function1 0x108b0000 text (file1.o)
function2 0x108d0000 text (file2.o)
function3 0x108f0000 text (file3.o)
value = 0 = 0x0
-> l function3
function3:
0x108f0000 55 PUSH EBP
0x108f0001 89 e5 MOV EBP, ESP
0x108f0003 56 PUSH ESI
0x108f0004 57 PUSH EDI
0x108f0005 e8 f6 ff fb ff CALL function1
0x108f000a e8 f1 ff fd ff CALL function2
0x108f000f 31 c0 XOR EAX, EAX
0x108f0011 5f POP EDI
0x108f0012 5e POP ESI
0x108f0013 89 ec MOV ESP, EBP
value = 0 = 0x0
-> function3
function1 called
function2 called
value = 0 = 0x0
->
Although l() helpfully displays function names, no symbols are actually loaded into memory with the object. Instead, a call to the last address associated with the function is loaded. So, a previously loaded function may be overridden by loading another function of the same name.
-> unld "file3.o"
value = 0 = 0x0
-> ld < mock.o
value = 292537592 = 0x116fc4f8
-> ld < file3.o
value = 292539496 = 0x116fcc68
-> lkup "function"
function1 0x108f0000 text (mock.o)
function1 0x108b0000 text (file1.o)
function2 0x108f0020 text (mock.o)
function2 0x108d0000 text (file2.o)
function3 0x10910000 text (file3.o)
value = 0 = 0x0
-> l function3
function3:
0x10910000 55 PUSH EBP
0x10910001 89 e5 MOV EBP, ESP
0x10910003 56 PUSH ESI
0x10910004 57 PUSH EDI
0x10910005 e8 f6 ff fd ff CALL function1
0x1091000a e8 11 00 fe ff CALL function2
0x1091000f 31 c0 XOR EAX, EAX
0x10910011 5f POP EDI
0x10910012 5e POP ESI
0x10910013 89 ec MOV ESP, EBP
value = 0 = 0x0
-> function3
mock function1 called
mock function2 called
value = 0 = 0x0
->
Note that for this method to work, the called and calling functions cannot be compiled into the same object. You might also note that the addresses to be called don't match those in the symbol table. This is the result of executing the above in VxSim. The VxSim loader actually calls the loader of the underlying operating system. So, these addresses don't match those in the symbol table and the assembly reflects the underlying Pentium architecture on which WorkBench is being run.
A function call may also be overridden by directly manipulating the address to be called in memory. This method is going to be implementation dependent. Below, this is demonstrated for source compiled for PPC using the gcc -mlongcall option. This has been run on an actual target, not VxSim.
-> ld < file1.o
value = 33538216 = 0x1ffc0a8 = function1 + 0x498
-> ld < file2.o
value = 33548336 = 0x1ffe830 = function2 + 0x80
-> ld < mock.o
value = 33549600 = 0x1ffed20 = function2 + 0x570
-> ld < file3.o
value = 33550744 = 0x1fff198 = function2 + 0x9e8
->
-> lkup "function"
function1 0x01ffbef8 text (mock.o)
function1 0x01ffbc10 text (file1.o)
function2 0x01ffbf58 text (mock.o)
function2 0x01ffe7b0 text (file2.o)
function3 0x01ffe558 text (file3.o)
value = 0 = 0x0
->
-> function3
mock function1 called
mock function2 called
value = 0 = 0x0
->
-> l function3
function3:
0x1ffe558 9421ffe8 stwu r1,-24(r1)
0x1ffe55c 7c0802a6 mfspr r0,LR
0x1ffe560 93a1000c stw r29,12(r1)
0x1ffe564 93c10010 stw r30,16(r1)
0x1ffe568 93e10014 stw r31,20(r1)
0x1ffe56c 9001001c stw r0,28(r1)
0x1ffe570 7c3f0b78 or r31,r1,r1
0x1ffe574 3d200200 lis r9,512
0x1ffe578 3ba9bef8 addi r29,r9,-16648
0x1ffe57c 7fa803a6 mtspr LR,r29
value = 33547648 = 0x1ffe580 = function3 + 0x28
->
-> *0x1ffe578
function3 + 0x20 = 0x1ffe578: value = 1000980216 = 0x3ba9bef8
-> *0x1ffe578 = 0x3ba9bc10
function3 + 0x20 = 0x1ffe578: value = 1000979472 = 0x3ba9bc10
-> *0x1ffe578
function3 + 0x20 = 0x1ffe578: value = 1000979472 = 0x3ba9bc10
->
-> function3
function1 called
mock function2 called
value = 0 = 0x0
->
Obviously, directly manipulating pointers in memory is going to quickly become tedious. Additionally, memory protection will prevent you from changing RTPs or objects loaded in VxSim. (Hence, why I ran this on actual hardware.) I mention the possibility, primarily because it seems to best match your question's statement.
Finally, for non-trivial unit testing, you may want to consider a tool designed specifically for the task. Try a search on "vxworks unit test framework". I don't have deep experience with any particular tool (and don't want to come across spammy). Perhaps, someone else here can provide a good suggestion.
While playing around with template recursion in D, I found that the intermediate results of the classical factorial are still in the object file. I suppose they are also in the executable...?
I can see that the actually executed code contains only the value (or a pointer to it) but:
Shouldn't there be a single mov statement without the intermediate data being saved for no reason?
This is the code:
int main()
{
static int x = factorial!(5);
return x;//factorial!(5);
}
template factorial(int n)
{
static if (n == 1)
const factorial = 1;
else
const factorial = n * factorial!(n-1);
}
and this is the output of obj2asm test.o:
( for your convenience: 1! = 1h, 2! = 2h, 3! = 6h, 4! = 18h, 5! = 78h )
FLAT group
;File = test_fac_01.d
extrn _main
public _deh_beg
public _deh_end
public _tlsstart
public _tlsend
public _D11test_fac_014mainFZi1xi
extrn _GLOBAL_OFFSET_TABLE_
public _Dmain
public _D11test_fac_0112__ModuleInfoZ
extrn _Dmodule_ref
public _D11test_fac_017__arrayZ
public _D11test_fac_018__assertFiZv
public _D11test_fac_0115__unittest_failFiZv
extrn _d_array_bounds
extrn _d_unittestm
extrn _d_assertm
.text segment
assume CS:.text
:
mov EAX,offset FLAT:_D11test_fac_0112__ModuleInfoZ[018h]#32
mov ECX,offset FLAT:_Dmodule_ref#32
mov RDX,[RCX]
mov [RAX],RDX
mov [RCX],RAX
ret
.text ends
.data segment
_D11test_fac_0112__ModuleInfoZ:
db 004h,000h,000h,0ffffff80h,000h,000h,000h,000h ;........
db 074h,065h,073h,074h,05fh,066h,061h,063h ;test_fac
db 05fh,030h,031h,000h,000h,000h,000h,000h ;_01.....
db 000h,000h,000h,000h,000h,000h,000h,000h ;........
dq offset FLAT:_D11test_fac_0112__ModuleInfoZ#64
.data ends
.bss segment
.bss ends
.rodata segment
.rodata ends
.tdata segment
_tlsstart:
db 000h,000h,000h,000h,000h,000h,000h,000h ;........
db 000h,000h,000h,000h,000h,000h,000h,000h ;........
.tdata ends
.tdata. segment
_D11test_fac_014mainFZi1xi:
db 078h,000h,000h,000h ;x...
.tdata. ends
.text._Dmain segment
assume CS:.text._Dmain
_Dmain:
push RBP
mov RBP,RSP
mov RAX,FS:[00h]
mov RCX,_D11test_fac_014mainFZi1xi#GOTTPOFF[RIP]
mov EAX,[RCX][RAX]
pop RBP
ret
nop
nop
nop
.text._Dmain ends
.data._D11test_fac_0117__T9factorialVi5Z9factorialxi segment
_D11test_fac_0117__T9factorialVi5Z9factorialxi:
db 078h,000h,000h,000h ;x...
.data._D11test_fac_0117__T9factorialVi5Z9factorialxi ends
.data._D11test_fac_0117__T9factorialVi4Z9factorialxi segment
_D11test_fac_0117__T9factorialVi4Z9factorialxi:
db 018h,000h,000h,000h ;....
.data._D11test_fac_0117__T9factorialVi4Z9factorialxi ends
.data._D11test_fac_0117__T9factorialVi3Z9factorialxi segment
_D11test_fac_0117__T9factorialVi3Z9factorialxi:
db 006h,000h,000h,000h ;....
.data._D11test_fac_0117__T9factorialVi3Z9factorialxi ends
.data._D11test_fac_0117__T9factorialVi2Z9factorialxi segment
_D11test_fac_0117__T9factorialVi2Z9factorialxi:
db 002h,000h,000h,000h ;....
.data._D11test_fac_0117__T9factorialVi2Z9factorialxi ends
.data._D11test_fac_0117__T9factorialVi1Z9factorialxi segment
_D11test_fac_0117__T9factorialVi1Z9factorialxi:
db 001h,000h,000h,000h ;....
.data._D11test_fac_0117__T9factorialVi1Z9factorialxi ends
.ctors segment
dq offset FLAT:#64
.ctors ends
.text._D11test_fac_017__arrayZ segment
assume CS:.text._D11test_fac_017__arrayZ
_D11test_fac_017__arrayZ:
push RBP
mov RBP,RSP
sub RSP,010h
mov RSI,RDI
mov RDI,offset FLAT:_D11test_fac_0112__ModuleInfoZ#64
call _d_array_bounds#PC32
nop
nop
.text._D11test_fac_017__arrayZ ends
.text._D11test_fac_018__assertFiZv segment
assume CS:.text._D11test_fac_018__assertFiZv
_D11test_fac_018__assertFiZv:
push RBP
mov RBP,RSP
sub RSP,010h
mov RSI,RDI
mov RDI,offset FLAT:_D11test_fac_0112__ModuleInfoZ#64
call _d_assertm#PC32
nop
nop
.text._D11test_fac_018__assertFiZv ends
.text._D11test_fac_0115__unittest_failFiZv segment
assume CS:.text._D11test_fac_0115__unittest_failFiZv
_D11test_fac_0115__unittest_failFiZv:
push RBP
mov RBP,RSP
sub RSP,010h
mov RSI,RDI
mov RDI,offset FLAT:_D11test_fac_0112__ModuleInfoZ#64
call _d_unittestm#PC32
leave
ret
.text._D11test_fac_0115__unittest_failFiZv ends
end
You shouldn't use templates when what you want is compile-time function execution. Just write the function as you would and call it in a static context.
int main()
{
static int x = factorial(5); // static causes CTFE
return x;
}
int factorial(int n)
{
if (n == 1)
return 1;
else
return n * factorial(n-1);
}
This won't result in any extra symbols because factorial is evaluated at compile time. There are no symbols other than factorial itself. Your template trick instantiates symbols to achieve the same effect, but it's not symbols you want.
Alternatively, if you still want to use templates, but don't want symbols then you can use manifest constants via enum.
template factorial(int n)
{
static if (n == 1)
enum factorial = 1;
else
enum factorial = n * factorial!(n-1);
}
Notice the change from const to enum. enum values are purely compile-time, so they produce no symbols or data in the object files.
I'm debugging this code :
len = NGX_SYS_NERR * sizeof(ngx_str_t);
ngx_sys_errlist = malloc(len);
if (ngx_sys_errlist == NULL) {
goto failed;
}
for (err = 0; err < NGX_SYS_NERR; err++) {
But in gdb if (ngx_sys_errlist == NULL) { is skipped directly:
(gdb)
59 ngx_sys_errlist = malloc(len);
(gdb) n
64 for (err = 0; err < NGX_SYS_NERR; err++) {
I also have experienced this before,but never knows the reason,anyone knows?
Is it a bug?
UPDATE
0x000000000041be9d <ngx_strerror_init+0>: mov %rbx,-0x30(%rsp)
0x000000000041bea2 <ngx_strerror_init+5>: mov %rbp,-0x28(%rsp)
0x000000000041bea7 <ngx_strerror_init+10>: mov %r12,-0x20(%rsp)
0x000000000041beac <ngx_strerror_init+15>: mov %r13,-0x18(%rsp)
0x000000000041beb1 <ngx_strerror_init+20>: mov %r14,-0x10(%rsp)
0x000000000041beb6 <ngx_strerror_init+25>: mov %r15,-0x8(%rsp)
0x000000000041bebb <ngx_strerror_init+30>: sub $0x38,%rsp
0x000000000041bebf <ngx_strerror_init+34>: mov $0x840,%edi
0x000000000041bec4 <ngx_strerror_init+39>: callq 0x402388 <malloc#plt>
0x000000000041bec9 <ngx_strerror_init+44>: mov %rax,0x26e718(%rip) # 0x68a5e8 <ngx_sys_errlist>
0x000000000041bed0 <ngx_strerror_init+51>: mov $0x840,%r12d
0x000000000041bed6 <ngx_strerror_init+57>: test %rax,%rax
0x000000000041bed9 <ngx_strerror_init+60>: je 0x41bf56 <ngx_strerror_init+185>
0x000000000041bedb <ngx_strerror_init+62>: mov $0x0,%r13d
0x000000000041bee1 <ngx_strerror_init+68>: mov $0x0,%r14d
0x000000000041bee7 <ngx_strerror_init+74>: mov $0x0,%r15d
0x000000000041beed <ngx_strerror_init+80>: mov %r13d,%edi
0x000000000041bef0 <ngx_strerror_init+83>: callq 0x402578 <strerror#plt>
UPDATE
Nobody else ever met the same thing in using gdb? It happens to me frequently when debugging.
Most likely the two statements were optimized into a single set-and-test expression, which then can't be decomposed into the original two lines. The generated pseudocode is likely to be something like
call _malloc
jz _failed
mov acc, _ngx_sys_errlist
where the test now happens before the assignment; do you let the source level trace go backwards to reflect this?
please check,
a) if you are debugging release build (if there exists one)
b) if your source file is modified
if you still have the issue, please provide the details (Complier with version, degugger version , platform and code ...)
I'm currently coding an irc bot in asm
I have already done this once in C++, so I know how to solve most problems I encounter, but I need a substr()[*] function like the one seen in C++. I need the substr function to receive the server name from a PING request so I can respond with the corresponding PONG response
But I don't know how to implent it in MASM, I heard of something called macroassembling, It seems substr is often used in those functions
Does anyone have any idea how I can get my substr function to work
[*] string substr ( size_t pos = 0, size_t n = npos )
This is how I use the substr() funcion in C++:
if(data.find("PING :") != std::string::npos){
string pong = "PONG :" + data.substr( (data.find_last_of(":")+1), (data.find_last_of("\r")-1) );
SCHiMBot.Pong(pong); // Keep the connection alive!
}
Where data is a string holding all the information the server sends me, and SCHiMBot is a class I use to talk with the server
This code is c&p'ed directly out of a bot I coded, so it should be flawless
This really isn't nearly as easy to answer is it might initially seem. The problem is pretty simple: a function like substr doesn't really exist in isolation -- it's part of a string library, and to make it useful, you just about need to at least sketch out how the library as a whole fits together, how you represent your data, etc. I.e., substr creates a string, but to do so you need to decide what a string is.
To avoid that problem, I'm going to sort of ignore what you actually asked, and give a somewhat simpler answer that's more suited to assembly language. What you really need is to start with one buffer of data, find a couple of "markers" in that buffer, and copy what's in between those markers to a designated position in another buffer. First we need the code to do the "find_last":
; expects:
; ESI = address of buffer
; ECX = length of data in buffer
; AH = character to find
; returns:
; ESI = position of item
;
find_last proc
mov al, [esi+ecx]
cmp ah, al
loopnz find_last
ret
find_last endp
Now to copy the substring to the transmission buffer, we do something like this:
CR = 13
copy_substr proc
mov esi, offset read_buffer
mov ecx, bytes_read
mov ah, CR
call find_last ; find the carriage-return
mov edx, esi ; save its position
mov esi, offset read_buffer
mov ecx, bytes_read
mov ah, ':'
call find_last ; find the colon
inc esi ; point to character following colon
sub edx, esi ; get distance from colon+1 to CR
mov ecx, edx
; Now: ESI = address following ':'
; ECX = distance to CR
mov edi, (offset trans_buffer) + prefix_length
rep movsb ; copy the data
ret
copy_substr endp
data.substr( (data.find_last_of(":")+1)
The first parameter of substr is the starting position. If it is a value passed the last element of the string, out_of_range exception will be thrown. You should verify that this is not happening.
if(data.find("PING :") != std::string::npos)
{
size_t s1 = data.find_last_of(":");
size_t s2 = data.find_last_of("\r");
if (s1 != string::npos &&
s2 != string::npos &&
s1+1 < data.size())
{
string pong = "PONG :" + data.substr(s1+1, s2-1);
SCHiMBot.Pong(pong); // Keep the connection alive!
}
}