Does WinDBG support multi-line commands? - windbg

For the sake of readability, it would be nice to be able to have multi-line "script" (whatever the syntax of WinDBG is called) code.
For example, I want to search through a chunk of memory looking for things that look somewhat like a wxArrayString...
r $t1 = 0xe53801c
r $t2 = 0x2e800
.for (r $t3 = 0; #$t3 < 0x400; r $t3 = #$t3 + 1) {
.if (##c++(
((int)(((MyModule!wxArrayString*)(#$t1+#$t2+(#$t3*8)))->m_compareFunction) >= 0x10000) &&
((int)(((MyModule!wxArrayString*)(#$t1+#$t2+(#$t3*8)))->m_pItems) >= 0x10000) &&
(((MyModule!wxArrayString*)(#$t1+#$t2+(#$t3*8)))->m_nCount <= 5000) &&
(((MyModule!wxArrayString*)(#$t1+#$t2+(#$t3*8)))->m_nCount > 0) &&
(((MyModule!wxArrayString*)(#$t1+#$t2+(#$t3*8)))->m_nSize <= 10000) &&
(((MyModule!wxArrayString*)(#$t1+#$t2+(#$t3*8)))->m_nSize > 0)
)) {
dx ((MyModule!wxArrayString*)(#$t1+#$t2+(#$t3*8)))
}
}
Smushing that into a single line isn't too hard, but it would be nice if I didn't have to do it every time I wanted to test a change in the code.
Is there a way to do this (with line continuations or some other magic)?

If you have an editor that allows and supports files with different line endings (in one file!), it's feasible:
Insert Macintosh linebreaks (CR; 0x0D) where you want to see line breaks and Unix line breaks (LF; 0x0A) where you want WinDbg to end a statement.
$<, $><, $$<, $$><, $$ >a< (MSDN; not some injection) has some details:
The $$>< and $>< tokens execute the commands that are found in the script file literally, which means they open the script file, replace all carriage returns with semicolons, and execute the resulting text as a single command block.
Actually that statement is wrong. It replaces 0x0A by semicolons and that is LF (line feed) and not carriage return (CR).
Example:
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 2E 65 63 68 6F 20 22 57 6F 77 0D 2E 65 63 68 6F .echo "Wow..echo
00000010 20 74 68 65 72 65 20 69 73 20 61 20 6C 69 6E 65 there is a line
00000020 62 72 65 61 6B 22 0A 72 20 24 74 30 0A 6B 20 4C break".r $t0.k L
00000030 31
which looks like 4 lines but will be executed as 1 line:
2:004> $$>a< b:\newline.windbg
Wow .echo there is a linebreak
$t0=00000000
# ChildEBP RetAddr
00 0116f508 7726c088 ntdll!LdrpDoDebuggerBreak+0x2b
The WinDbg command parser, scripting parser and whatever parsers are implemented ... erm ... in a quite simplistic way, I assume. They didn't think much about escape characters etc. Note that they do not care about the " of .echo and would even replace even replace LF in the middle of a string. There are plenty of examples which are like that.
Maybe you want to look into Python scripting with pykd, implement a WinDbg extension or similar.

are those numbers/address 10000 for m_compareFunction , m_pItems an example and not actual value ??
m_compareFunction is a Function Pointer
0:000> ?? labels[0].m_compareFunction
<function> * 0x00000000`00000000
m_pItems is a wxString *
0:000> ?? labels[0].m_pItems
class wxString * 0x000001c8`2553f598
=00007ff7`cc3b8a60 npos : 0xffffffff`ffffffff
+0x000 m_impl : std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >
+0x028 m_convertedToChar : wxString::ConvertedBuffer<char>
also adding $t1+$t2 could be eliminated
anyway put your script in a txtfile like myscript.wds and use
$$>a< myscript.wds
to execute it
you can write script as multiline
:\>cat d:\myscript.wds
r? $t0 = labels
?? #$t0
?? #$t0[0]
?? #$t0[1].m_pItems
?? #$t0[3].m_nCount
:\>
executed
0:000> $$>a< d:\myscript.wds
class wxArrayString [8] 0x00000035`350fe650
+0x000 m_compareFunction : (null)
+0x008 m_nSize : 0x20
+0x010 m_nCount : 0x13
+0x018 m_pItems : 0x000001c8`2553f598 wxString
+0x020 m_autoSort : 0
class wxArrayString
+0x000 m_compareFunction : (null)
+0x008 m_nSize : 0x20
+0x010 m_nCount : 0x13
+0x018 m_pItems : 0x000001c8`2553f598 wxString
+0x020 m_autoSort : 0
class wxString * 0x000001c8`26f40fa8
=00007ff7`cc3b8a60 npos : 0xffffffff`ffffffff
+0x000 m_impl : std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >
+0x028 m_convertedToChar : wxString::ConvertedBuffer<char>
unsigned int64 0
also if you use r? you can eliminate all the casting
0:000> r #$t0 = 0x00000035`350fe654
0:000> r? $t19 = (widgets!wxArrayString *)#$t0
0:000> ?? #$t19
class wxArrayString * 0x00000035`350fe654
+0x000 m_compareFunction : 0x00000020`00000000 int +2000000000
+0x008 m_nSize : 0x00000013`00000000
+0x010 m_nCount : 0x2553f598`00000000
+0x018 m_pItems : 0x350ff800`000001c8 wxString
+0x020 m_autoSort : 35

Related

How do loop over the search results for a byte string and offset the resultant pointer (in WinDbg)?

I'm attempting to search for an arbitrarily long byte string in WinDbg and print out the address if an integer in the vicinity meets some criteria.
Pseudo-register $t0 contains the starting address I want to search.
Here's something that, based on the Windows docs, maybe could work (though it clearly doesn't).
.foreach (place { s -[1] #$t0 L?30000 00 00 00 00 00 20 00 00 }) { .if ( (place +0x8) <= 0x1388) { .printf "0x%x\n", place } }
Search
First, the search command doesn't quite work correctly. I only want the address of the match (not the data).
s -[1] #$t0 L?30000 00 00 00 00 00 20 00 00
The docs say that the 1 flag will only return the address. When I issue that command, WinDbg replies
^ Syntax error in 's -1 #$t0 L?30000 00 00 00 00 00 20 00 00 '
If I leave out the -1, it finds two matches.
What am I doing wrong here?
Condition
I don't think the condition is behaving the way I want. I want to look at the third dword starting at place, i.e. place+8, and verify that it's smaller than 5000 (decimal). The .if inside the .foreach isn't printing a meaningful value for place (i.e. the address returned from the search). I think it's dereferencing place first and comparing the value of that integer to 5000. How do I look at the value of, say, *(int*)(place+8)?
Documentation?
The docs are not helping me very much. They only have sparse examples, none of which correspond to what I need.
Is there better documentation somewhere besides MS's Hardware Dev Center?
you can start writing JavaScript for a more legible way of scripting
old way
0:000> s -b vect l?0x1000 4d
00007ff7`8aaa0000 4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00 MZ..............
00007ff7`8aaa00d4 4d 90 80 d2 df f9 82 d3-4d 90 80 d2 52 69 63 68 M.......M...Rich
00007ff7`8aaa00dc 4d 90 80 d2 52 69 63 68-4c 90 80 d2 00 00 00 00 M...RichL.......
0:000> s -[1]b vect l?0x1000 4d
0x00007ff7`8aaa0000
0x00007ff7`8aaa00d4
0x00007ff7`8aaa00dc
using javascript
function search(addr,len)
{
var index = []
var mem = host.memory.readMemoryValues(addr,len)
for(var i = 0; i < len; i++)
{
if(mem[i] == 0x4d)
{
index.push(addr+i)
}
}
return index
}
executed will return address like which you can manipulate further
0:000> dx -r1 #$scriptContents.search(0x00007ff78aaa0000,1000)
#$scriptContents.search(0x00007ff78aaa0000,1000) : 140701160046592,140701160046804,140701160046812
length : 0x3
[0x0] : 0x7ff78aaa0000
[0x1] : 0x7ff78aaa00d4
[0x2] : 0x7ff78aaa00dc
improving the script a little to find something based on first result
we will try to find the index of Rich string that follows the character 'M'
modified script
function search(addr,len)
{
var index = []
var Rich = []
var result = []
var mem = host.memory.readMemoryValues(addr,len)
for(var i = 0; i < len; i++)
{
if(mem[i] == 0x4d)
{
index.push(addr+i)
var temp = host.memory.readMemoryValues(addr+i+4,1,4)
host.diagnostics.debugLog(temp +"\t")
if(temp == 0x68636952)
{
Rich.push(addr+i)
}
}
}
result.push(index)
result.push(Rich)
return result
}
result only the third occurance of char "M" is followed by Rich string
0:000> dx -r2 #$scriptContents.search(0x00007ff78aaa0000,1000)
3 3548576223 1751345490 #$scriptContents.search(0x00007ff78aaa0000,1000) : 140701160046592,140701160046804,140701160046812,140701160046812
length : 0x2
[0x0] : 140701160046592,140701160046804,140701160046812
length : 0x3
[0x0] : 0x7ff78aaa0000
[0x1] : 0x7ff78aaa00d4
[0x2] : 0x7ff78aaa00dc
[0x1] : 140701160046812
length : 0x1
[0x0] : 0x7ff78aaa00dc
0:000> s -b vect l?0x1000 4d
00007ff7`8aaa0000 4d 5a 90 00 03 00 00 00-04 00 00 00 ff ff 00 00 MZ..............
00007ff7`8aaa00d4 4d 90 80 d2 df f9 82 d3-4d 90 80 d2 52 69 63 68 M.......M...Rich
00007ff7`8aaa00dc 4d 90 80 d2 52 69 63 68-4c 90 80 d2 00 00 00 00 M...RichL.......
load the extensension jsprovider.dll .load jsprovider
write a script say foo.js
load the script .scriptload ...\path\foo.js
execute any functions inside the js you wrote with dx #$scriptContents.myfunc(myargs)
see below using cdb just for ease of copy paste windbg works just as is
F:\>type mojo.js
function hola_mojo ()
{
host.diagnostics.debugLog("hola mojo this is javascript \n")
}
F:\>cdb -c ".load jsprovider;.scriptload .\mojo.js;dx #$scriptContents.hola_mojo();q" cdb | f:\usr\bin\grep.exe -A 6 -i reading
0:000> cdb: Reading initial command '.load jsprovider;.scriptload .\mojo.js;dx #$scriptContents.hola_mojo();q'
JavaScript script successfully loaded from 'F:\mojo.js'
hola mojo this is javascript
#$scriptContents.hola_mojo()
quit:
If I read this part of the documentation
s [-[[Flags]Type]] Range Pattern
correctly, you cannot leave out Type when specifying flags. That's because the flags are inside two square brackets. Otherwise it would have been noted as s [-[Flags][Type]] Range Pattern.
Considering this, the example works:
0:000> .dvalloc 2000
Allocated 2000 bytes starting at 00ba0000
0:000> eb 00ba0000 01 02 03 04 05 06 07 08 09
0:000> eb 00ba1000 01 02 03 04 05 06 07 08 09
0:000> s -[1]b 00ba0000 L?2000 01 02 03 04 05 06 07 08
0x00ba0000
0x00ba1000
Also note that you'll have a hidden bug for the use of place: it should be ${place}. By default, that will work with the address (line break for readability on SO):
0:000> .foreach (place {s -[1]b 00ba0000 L?2000 01 02 03 04 05 06 07 08 })
{ .if ( (${place} +0x8) < 0xba1000) { .printf "0x%x\n", ${place} } }
0xba0000
In order to read a DWord from that address, use the dwo() MASM oerator (line break for readability on SO):
0:000> .foreach (place {s -[1]b 00ba0000 L?2000 01 02 03 04 05 06 07 08 })
{ .if ( (dwo(${place} +0x8)) < 0xba1000)
{ .printf "0x%x = 0x%x\n", ${place}, dwo(${place}+8) } }
0xba0000 = 0x9
0xba1000 = 0x9

Extra computation steps on adding brackets?

Ok, so just a question popped up in my mind while writing some code.
Does the CPU compute this
gap = (gap*3) + 1;
with the same efficiency as the below expression without the brackets?
gap = gap*3 + 1;
Update to be more clarifying:
Often while writing arithmetic expressions, we tend to add brackets to make the code easier to read, even if the brackets do not change what the expression evaluates to. So the question is, does adding such brackets have any affect on the performance?
As mentioned above in the comments:
file test1.c:
int main(void)
{
int gap = 1;
gap = (gap*3) + 1;
return gap;
}
file test2.c:
int main(void)
{
int gap = 1;
gap = gap*3 + 1;
return gap;
}
Using gcc and its -S option ("Compile only; do not assemble or link"): gcc -S test1.c && gcc -S test2.c. Comparing those two files:
$ diff test1.s test2.s
1c1
< .file "test1.c"
---
> .file "test2.c"
(i.e. only the file names differ in the first line)
When you still don't believe me (for this particular example), then you can further compile & assemble: gcc test1.c -o test1 && gcc test2.c -o test2. Comparing those binary files (or rather ELF executables) will give you one byte difference, i.e. the file name again:
$ hexdump -C test1 > hex1.txt && hexdump -C test2 > hex2.txt
$ diff hex1.txt hex2.txt
387c387
< 00001fc0 79 5f 65 6e 74 72 79 00 74 65 73 74 31 2e 63 00 |y_entry.test1.c.|
---
> 00001fc0 79 5f 65 6e 74 72 79 00 74 65 73 74 32 2e 63 00 |y_entry.test2.c.|

Searching memory including unknown values

In WinDbg I can search the memory for bytes using the s command, e.g.
s 0012ff40 L?2000 48 65 6c 6c 6f
Is there also a way to include unknown bytes in the search sequence, e.g.
s 0012ff40 L?2000 48 65 ?? ?? ?? 6c 6f
where ?? is a byte with an arbitrary value?
Idea
How about doing ((memory XOR 48 65 00 00 00 6c 6f) AND FF FF 00 00 00 FF FF) and compare that against 00 00 00 00 00 00 00? But I don't know how to do that in WinDbg either.
Am not sure if the search command supports wild card. But you can use .foreach command, to achieve what you want.
Here is a sample that i used to search a memory pattern such as ff ?? 00
.foreach (hit {s -[1]b 00007ffabc520000 L100 ff }) {db hit L3; s ${hit}+2 L1 00}
Here is a brief description of how it works :
NOTE - Open up the debugger help from windbg to get complete documentation. That is within Windbg, Help | Contents
{s -[1]b 00007ffabc520000 L100 ff }
Use -[1] flag with s, so that only the memory address is given as the output.
s ${hit}+2 L1 00
For each hit, pass that memory address to the next search command. Increase the memory by the number of bytes that you want to skip and mention the last part of search pattern.
db hit L3
From the memory that has the beginning of the patter, dump the entire length. This is just to confirm that we are getting the right results!
Hope this helps. In case you need further clarification, i can try to provide that as well.
We can use pykd to achieve this. Find the downloads linked from PyKD Wiki or PyKD Downloads. When using WinDbg Preview, copy the DLLs into
%LOCALAPPDATA%\DBG\EngineExtensions
for 64 bit or
%LOCALAPPDATA%\DBG\EngineExtensions32
for 32 Bit.
Since this is only the WinDbg extension, you also need the Python module as well:
pip install pykd
Use the power of Python to do what WinDbg can't do. Save the following script in a good place for WinDbg, i.e. in a short path without spaces.
from pykd import *
import sys
import re
import struct
if len(sys.argv)<4:
print("Wildcard search for memory")
print("Usage:", sys.argv[0], "<address> <length> <pattern> [-v]", sep=" ")
print(" <address>: Memory address where searching begins.")
print(" This can be a WinDbg expression like ntdll!NtCreateThreadEx.")
print(" <length> : Number of bytes that will be considered as the haystack.")
print(" <pattern>: Bytes that you're looking for. May contain ?? for unknown bytes.")
print(" [-v] : (optional) Verbose output")
print()
print("Examples:")
print(" ", sys.argv[0], "00770000 L50 01 02 03 ?? 05")
print(" will find 01 02 03 04 05 or 01 02 03 FF 05, if present in memory")
sys.exit(0)
verbose = False
if sys.argv[-1][0:2] == "-v":
verbose = True
if verbose:
for n in range(1, len(sys.argv)):
print(f"param {n}: " + sys.argv[n])
address = expr(sys.argv[1])
if verbose: print("Start address:", "0x{:08x}".format(address), sep=" ")
length = sys.argv[2]
length = length.replace("L?","") # consider large address range syntax
length = length.replace("L","") # consider address range syntax
length = expr(length)
if verbose: print("Length:", "0n"+str(length), "bytes", sep=" ")
regex = b""
for n in range(3, len(sys.argv) - 1 if verbose else 0):
if sys.argv[n] == "??":
regex += bytes(".", "ascii")
else:
char = struct.pack("B", expr(sys.argv[n]))
if char == b".":
regex += struct.pack("B", ord("\\"))
regex += char
if verbose: print("Regex:", regex, sep=" ")
memorycontent = loadBytes(address, length)
if verbose: print("Memory:", memorycontent, sep=" ")
result = re.search(regex, bytes(memorycontent))
print("Found:", ' '.join("0x{:02x}".format(x) for x in result.group(0)), "at address", "0x{:08x}".format(address+result.start()))
The script constructs a Regex for a Bytes object. It uses . for the wildcard and escapes literal . to \..
Let's prepare a proper sample in WinDbg:
0:006> .dvalloc 1000
Allocated 1000 bytes starting at 00900000
0:000> eu 0x00900000 "Test.with.regex"
0:000> db 0x00900000 L0n30
00900000 54 00 65 00 73 00 74 00-2e 00 77 00 69 00 74 00 T.e.s.t...w.i.t.
00900010 68 00 2e 00 72 00 65 00-67 00 65 00 78 00 h...r.e.g.e.x.
Load the PyKD extension, so we'll be able to run the script:
0:006> .load pykd
and run the script:
0:000> !py d:\debug\scripts\memwild.py 00900000 L10 2e ?? 77
Found: 0x2e 0x00 0x77 at address 0x00900008
If the range of the search is not insanely large you could copy/paste the hex dump into sublime text and just do a find with regex mode enabled. For example I was looking for (1200 < X < 2400)
add esp, X
ret
In sublime text I searched using the regex 81 c4 .. .. .. 00 c3 and found an address with instructions for
add esp,600h
ret

Functions to deal with Unicode string manipulation with PowerBuilder 12.1

I am currently working on converting our PowerBuilder 12.1 application, which does not currently support Unicode, into a Unicode supporting application.
I have made some modifications to save Unicode data to our database, as well to files, but I have hit a slight snag in processing strings.
For example, the character 𠆾 is a Surrogate Pair and PowerBuilder interprets this as 2 characters (similar to how .NET operates). Thus:
LEN("𠆾") = 2
To me, this part makes sense, as it is count each code unit as a character.
Currently we have come up with two solutions to handle doing string functions with Unicode characters:
Callable OLEObjects written in C# .NET
using the PBNI interface to call C# .NET (want to stay away from this solution if possible)
An example of the .NET code we are thinking of using for determining the string length is:
StringInfo.ParseCombiningCharacters("𠆾").Length = 1
We are just worried about the impact on performance with constantly calling the OLEObjects/PBNI to do all of our string processing. Have any of the other PowerBuilder developers here done Unicode string manipulation (LEN, MID, POS, etc), and how did you do it?
Thank you.
This is in response to Seki's hex conversion function. I'm posting it as an answer so I can include source code. I use the Microsoft cryptographic functions to display blobs in my debugging tools. Here's a simplified version of my blob window. The one I use is PFC-based and uses an object that wraps the MS Crypto library. It's from PB 12.5 but should import into any Unicode version of PB.
HA$PBExportHeader$w_show_blob.srw
forward
global type w_show_blob from window
end type
type sle_1 from singlelineedit within w_show_blob
end type
type mle_1 from multilineedit within w_show_blob
end type
end forward
global type w_show_blob from window
integer width = 3081
integer height = 1988
boolean titlebar = true
boolean controlmenu = true
boolean minbox = true
boolean maxbox = true
boolean resizable = true
boolean center = true
sle_1 sle_1
mle_1 mle_1
end type
global w_show_blob w_show_blob
type prototypes
FUNCTION boolean CryptBinaryToString ( &
Blob pbBinary, &
ulong cbBinary, &
ulong dwFlags, &
Ref string pszString, &
Ref ulong pcchString ) &
LIBRARY "crypt32.dll" ALIAS FOR "CryptBinaryToStringW"
end prototypes
type variables
CONSTANT Ulong CRYPT_STRING_HEXASCIIADDR = 11
end variables
forward prototypes
public subroutine of_showblob (ref blob abl_data)
end prototypes
public subroutine of_showblob (ref blob abl_data);unsignedlong lul_size, lul_bufsize
string ls_hex
try
lul_size = len(abl_data)
sle_1.text = string(lul_size)
setnull(ls_hex)
cryptbinarytostring( abl_data, lul_size, CRYPT_STRING_HEXASCIIADDR, ls_hex, lul_bufsize)
ls_hex = space(lul_bufsize)
if not cryptbinarytostring( abl_data, lul_size, CRYPT_STRING_HEXASCIIADDR , ls_hex, lul_bufsize) then
mle_1.text = "error converting blob data"
else
mle_1.text = ls_hex
end if
catch(runtimeerror re)
messagebox("oops", re.text)
end try
end subroutine
on w_show_blob.create
this.sle_1=create sle_1
this.mle_1=create mle_1
this.Control[]={this.sle_1,&
this.mle_1}
end on
on w_show_blob.destroy
destroy(this.sle_1)
destroy(this.mle_1)
end on
type sle_1 from singlelineedit within w_show_blob
integer x = 73
integer width = 517
integer height = 88
integer taborder = 10
integer textsize = -10
integer weight = 400
fontcharset fontcharset = ansi!
fontpitch fontpitch = variable!
fontfamily fontfamily = swiss!
string facename = "Arial"
long textcolor = 33554432
long backcolor = 553648127
string text = "none"
boolean displayonly = true
borderstyle borderstyle = stylelowered!
end type
type mle_1 from multilineedit within w_show_blob
integer x = 64
integer y = 96
integer width = 2898
integer height = 1716
integer taborder = 10
integer textsize = -10
integer weight = 400
fontcharset fontcharset = ansi!
fontpitch fontpitch = fixed!
fontfamily fontfamily = modern!
string facename = "Courier New"
long textcolor = 33554432
string text = "none"
boolean hscrollbar = true
boolean vscrollbar = true
boolean displayonly = true
borderstyle borderstyle = stylelowered!
end type
To use it, assuming your blob is lbl_myBlob:
open(w_show_blob)
w_show_blob.of_showblob(lbl_myBlob)
The output in the MLE looks like this:
0000 42 4d ee 00 00 00 00 00 00 00 76 00 00 00 28 00 BM........v...(.
0010 00 00 10 00 00 00 0f 00 00 00 01 00 04 00 00 00 ................
0020 00 00 78 00 00 00 00 00 00 00 00 00 00 00 00 00 ..x.............
0030 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80 ................
0040 00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80 ................
0050 00 00 80 80 80 00 c0 c0 c0 00 00 00 ff 00 00 ff ................
0060 00 00 00 ff ff 00 ff 00 00 00 ff 00 ff 00 ff ff ................
0070 00 00 ff ff ff 00 88 88 88 88 88 88 88 88 88 88 ................
0080 80 88 88 88 88 88 88 88 80 08 88 88 88 88 88 88 ................
0090 80 00 88 88 88 88 88 88 80 00 08 88 88 88 88 88 ................
00a0 80 00 00 88 88 88 88 88 80 00 00 08 88 88 88 88 ................
00b0 80 00 00 00 88 88 88 88 80 00 00 08 88 88 88 88 ................
00c0 80 00 00 88 88 88 88 88 80 00 08 88 88 88 88 88 ................
00d0 80 00 88 88 88 88 88 88 80 08 88 88 88 88 88 88 ................
00e0 80 88 88 88 88 88 88 88 88 88 88 88 88 88 ..............
Since the release 10, PB is unicode (utf-16le)-aware. So the legacy Len() is implicit LenW() (as other string functions, and dealing with legacy data could imply to use explicit LenA()).
Are you sure that you are getting some utf-16le encoding ? Given the following function, what does it return on a string containing your data, if you call it with hexdump_blob(blob(your_string))?
Paste this code into the source code of a new global function named hexdump_blob to have an hexadecimal display (hex editor like) for blob contents.
global type hexdump_blob from function_object
end type
forward prototypes
global function string hexdump_blob (blob abl_data, boolean ab_fill_lastline)
end prototypes
global function string hexdump_blob (blob abl_data, boolean ab_fill_lastline);//hexify a blob content
string ls_tohex = "0123456789ABCDEF"
string ls_msg = "", ls_line, ls_binary
long i, j, length
byte b
string ls_fill
if isnull( abl_data ) then return ""
if ab_fill_lastline then
ls_fill = " __"
else
ls_fill = " "
end if
length = len( abl_data )
for i = 1 to length
GetByte( abl_data, i, b )
ls_line += mid( ls_tohex, 1+ mod(int(b/16),16), 1)
ls_line += mid( ls_tohex, 1+ mod(b,16), 1)
ls_line += " "
ls_binary += string( iif(b>31 and b<128,char(b)," "))
if mod(i,16) = 0 and i > 0 then
ls_binary = replaceall( ls_binary, "~r", "·") //no cr/lf
ls_binary = replaceall( ls_binary, "~n", "·")
ls_binary = replaceall( ls_binary, "~t", "·")
ls_msg += "[" + string( i - 16, "0000") + "] " + ls_line + "~t" + ls_binary + "~r~n"
ls_line = ""
ls_binary = ""
end if
next
i -- // i - 1 due to the last loop in for
ls_line += fill(ls_fill, 3 * ( 16 - mod(i, 16) ) )
ls_msg += "[" + string( i - mod(i,16), "0000") + "] " + ls_line + "~t" + ls_binary
return ls_msg
end function
Also, here is the replaceall() function that is used by hexdump_blob()
global type replaceall from function_object
end type
forward prototypes
global function string replaceall (string as_source, string as_pattern, string as_replace)
end prototypes
global function string replaceall (string as_source, string as_pattern, string as_replace);//remplace toute les occurences de as_pattern de as_source par as_replace
string ls_target
long i, j
ls_target=""
i = 1
j = 1
do
i = pos( as_source, as_pattern, j )
if i>0 then
ls_target += mid( as_source, j, i - j )
ls_target += as_replace
j = i + len( as_pattern )
else
ls_target += mid( as_source, j )
end if
loop while i>0
return ls_target
end function
and the iif() that simulates the C ternary operator, or the visual basic iif()
global type iif from function_object
end type
forward prototypes
global function any iif (boolean ab_cond, any aa_true, any aa_false)
end prototypes
global function any iif (boolean ab_cond, any aa_true, any aa_false);
// simulates the VB iif or C ternary operator
if ab_cond then
return aa_true
else
return aa_false
end if
end function
Wouldn't you want to use the LenA() method?
http://www.techno-kitten.com/Changes_to_PowerBuilder/New_in_PowerBuilder_10/PB10New_-_Unicode_Support/PB10New_-_Unicode_Related_Chan/PB10New_-_String-Related_Funct/pb10new_-_modified_processing_.html

Insert shell code

I got a small question.
Say I have the following code inside a console application :
printf("Enter name: ");
scanf("%s", &name);
I would like to exploit this vulnerability and enter the following shell code (MessageboxA):
6A 00 68 04 21 2F 01 68 0C 21 2F 01 6A 00 FF 15 B0 20 2F 01
How can I enter my shell code (Hex values) through the console ?
If I enter the input as is, it treats the numbers as chars and not as hex values.
Thanks a lot.
You could use as stdin a file with the desired content or use the echo command.
Suppose your shell code is AA BB CC DD (obviously this is not a valid shellcode):
echo -e "\xAA\xBB\xCC\xDD" | prog