I have an ANSI string in an RCData resource and I'd like to store that string in a variable. I've got to the point where I can get the pointer to the resource and the size of the data:
; HMODULE GetModuleHandle(LPCSTR lpModuleName);
System::Call "kernel32::GetModuleHandle(i 0) i.r0"
; HRSRC FindResource(HMODULE hModule, LPCSTR lpName, LPCSTR lpType);
System::Call "kernel32::FindResource(i 0, t 'DATA', i 10) i.r1"
; HGLOBAL LoadResource(HMODULE hModule, HRSRC hResInfo);
System::Call "kernel32::LoadResource(i r0, p r1) i.r2"
; LPVOID LockResource(HGLOBAL hResData);
System::Call "kernel32::LockResource(i r2) p.r3"
; DWORD SizeofResource(HMODULE hModule, HRSRC hResInfo);
System::Call "kernel32::SizeofResource(i r0, i r1) i.r4"
Now I'm not very sure what to do. I'm quite new to NSIS and I think my problem is that I don't really understand how variables work in NSIS and what happens (what value it has) when a variable is used as output of a System call with different types. What (I think) I need is to copy $4 bytes from an address stored in $3 to a new buffer and (probably?) terminate it with zero. I thought something like this could work:
System::Alloc ${NSIS_MAX_STRLEN}
Pop $5
System::Copy /$4 $5 $3
But it doesn't. After some experiments, I got to the point when this is working:
System::Call "*$3(&m$4.r5)"
But I really don't have a good idea why this is working, if it is the right way how this task should be handled and why the Copy version above didn't work.
In the System::Copy code, $5 contains the memory address of the allocated buffer (as a string, as if someone did sprintf(reg5, "%i", address)). If you do MessageBox mb_ok $5 you will just see this address. However, if you do System::Call user32::MessageBoxA(p0,pr5,p0,i0) you should see your string.
The System::Call code converts the source and/or destination using the type you specify. This is a perfectly valid way to do it and is less work than the copy code.
This is perhaps easier to visualize if we had something that needed type conversion instead of basically a byte copy in your specific case.
Imagine if in C we had
typedef struct { int foo, bar; } MyS;
MyS*ptr = allocandfill();
and in NSIS $1 is the value of ptr:
System::Call '*$1(i.r2,i1234)'
we often refer to this as System struct syntax and the * can be thought of as de-referencing the memory starting at $1 and interpreting the memory as a struct based on the types we specify.
In my specific example here, we are saying the first member is an int and I don't want to change the value/source (the dot) but I want the current value as output stored in r2 ($2). This will basically perform a itoa where $2 is the destination. The second member is another int and I'm overwriting its current value with the number 1234. In C this would be performing ptr->bar = atoi("1234").
The third way to complete your task is to call a Windows function and get it to do the work:
System::Call `kernel32::lstrcpyA(m.r5,pr3)' ; or lstrcpynA if the string is not zero-terminated or you want to chop it to n characters
Related
I want to take an input and display the input with how many characters are in the string.
So far I'm able to produce the string, but I'm confused as to how I get the input?
You can use this function:
count db 0; (or resb 1), this is the place where will stay the result
count_string:
lodsb; // load char( letter )
cmp al, 0x00; // check string end; cause 0x00 its not a letter or number, 0 is 30h in ascii
jz done; // count done
inc byte [count]; adds 1 to count register
jmp count_string; // check next char
done:
ret; // exit function
And you can define a string this way:
data:
; or in the section .data
string DB "This is my string", 0; 0 means the end of the string
you can call the function this way:
mov si, string; move the string pointer to register
call count_string;
and if you are using nasm inside a OS like windows or ubuntu uou can watch this: https://www.youtube.com/watch?v=VAy4FGHDx1I
but in x86 i did a 4 byte( for letters ) command line, its really easy to get much more but it was just a quick experiment i used int 16h( keyboard )
I'm trying to encode with URLEncode a strings in NSIS. I'm using a NSIS plugin called URLEncode. The problem is that I try encode 2 vars, but the first encoded var lost the value after I encoded the second var.
Push "${AFF_NAME}"
Call URLEncode
Pop $3
;at this point the messagebox show the result good.
MessageBox MB_OK $3
ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" "ProductName"
Push $0
Call URLEncode
Pop $0
;now after second var encoded the result of first var $3 lost the value
MessageBox MB_OK $3
Please Help I'm very new using NSIS and I dont know how do it good. I searching info but without success.
Very thanks !
I'm not aware of a URLEncode plug-in but there is a helper function on the NSIS wiki called URLEncode and it fails to preserve the registers.
You can fix it by modifying the start and end of the function so it looks like this:
; Start
Function URLEncode
System::Store S ; Save registers
Pop $0 ;param
...
Done:
Push $9
System::Store L ; Restore registers
FunctionEnd
; End
Well, from few years I'm working with NSIS installers and I treat all variables as string in my scripts. Somewhere I read about this, that NSIS internally treat all variables as string, but don't know the exact fact.
Now my query is whenever we are copying some values into some variables or checking the variable's value using logic statements what should be the ideal way to do it. Let me show you an example what I'm talking about.
StrCpy $1 "Some string goes here"
StrCpy $2 999
${If} $1 == "String to match here"
${If} $2 == 999
${If} $2 == "999"
I guess I have no other option for StrCpy $1 case as there I'm copying string into a variable, but for case StrCpy $2, perhaps I can write StrCpy $2 "999" as well. Same thing goes for If statements.
I would like to know the correct convention for NSIS scripting.
Yes, internally everything is stored as strings and they converted to numbers when doing a number operation. Strings that cannot be converted to numbers are treated as 0.
StrCpy $2 999 and StrCpy $2 "999" is exactly the same thing, the quotes are only required when the string has spaces and the quotes are removed by the compiler automatically even when there are no spaces. This also means that ${If} $2 == 999 and ${If} $2 == "999" is the same.
When comparing you should use =, <>, <, <=, >= and > for numbers and == and != for strings.
${IfThen} 0x29A = 666 ${|} DetailPrint "True" ${|} ; 0x29A is 666 in hex
${IfThen} 0x29A == 666 ${|} DetailPrint "This will never print" ${|}
So say I have this value in a register ebx: 30303420
I want to convert that and print out the corresponding ascii values. So it SHOULD print out
004
30 == 0
30 == 0
34 == 4
20 == space character.
How would I get that to print on the screen?
This is 80x86 architecture, using assembly code.
Well, your question have a couple unclear details.
1- If you have 30303420 Hex value in ebx, then you have 4 Ascii characters, precisely "004 ", that is:
mov ebx,30303420H ;is exactly the same than:
mov ebx,"004 "
You have NOT any decimal value (wich one?), so there is not any conversion here.
2- If you want to show that ebx value in the screen, so it shows "004 ", then you must specify under which operating system your program will run in order to use the appropiate services. For example, if you want to use old-style MS-DOS INT 21H functions, that also run in a DOS Window in Windows, then this segment do that:
mov cx,4 ;counter = 4 characters
;
next:
rol ebx,8 ;rotate left EBX 1 byte: place next char in BL
mov dl,bl ;DL = char to show
mov ah,2 ;AH = VIDEO OUTPUT function
int 21H ;DOS kernel service Int: show the char
loop next ;repeat 4 times
However, if your program run under Linux, the method to show ebx value is entirely different. Also, your program may use a C library function in a different way, or be a Windows-compliant program, or use BIOS INT 10H service (in charge of the screen), or even directly access the video circuitry, etc, etc, etc...
SO I am working on writing an inline assembly function in c that reverses that contents of a string and puts the reversed string in a new character array, but I am getting extra characters added to the end of my reversed string.
int main(int argc, char **argv) {
char *new_str;
char old_str[20] = "Hello, World!";
mystrrev(new_str, old_str, strlen(old_str));
printf("New string: %s\n", &new_str);
return 0;
}
Assembly function
char *mystrrev(char *dest, const char *src, int size) {
int d0, d1, d2, d3;
__asm__ (
"add %%ebx, %%esi\n\t" /*Move to end of string*/
"std\n\t" /*Decrement esi after load*/
"lodsb\n\t" /*Load esi into al*/
"sub $1, %%ebx\n\t"
"mov %%al, %%cl\n\t" /*mov contents of al to cl*/
"1:\tstd\n\t" /*Begin loop, decrement esi after load*/
"lodsb\n\t" /*Load esi into al*/
"cld\n\t" /*Clear flg*/
"stosb\n\t" /*Store al in edi*/
"sub $1, %%ebx\n\t" /*subtract 1 from strlenght counter*/
"cmp $0, %%ebx\n\t" /*Compare ebx to 0*/
"jne 1b\n\t"
"mov %%ecx, %%edi\n\t" /*Add null terminating char to new str*/
: "=&S"(d0), "=&D"(d1), "=&a"(d2), "=&b" (d3) /*output*/
/*** &S --> ESI, &D --> EDI, &a --> eax ***/
: "0" (src), "1" (dest), "3" (size) /*input*/
: "memory"); /*clobber registers*/
return dest;
}
In this case Hello, World! gets printed out [!dlroW, olleH] but there are extra characters added at the end and I cannot figure out why.
Any thoughts??
The
mov %ecx, %edi /*Add null terminating char to new str*/
instruction does not write anything to memory; it just copies a zero into the register %edi itself. The correct syntax for a memory write, if I remember correctly, is something like
movb %cl, (%edi)
But it is really pointless to meticulously store the zero terminator in %cl during the copying, because you know it's going to be a zero anyway. So just
movb $0, (%edi)
ought to work just as well.
(Also, but unrelated, the string instructions are actually slower than equivalent combinations of separate load/store and increment/decrement operations. At least this used to be the case around the 486 or early Pentium era, and it would surprise me if it's not still true -- especially if you need to manipulate the direction flag each time anyway).
((Also also, it appears to be rather pointless to declare output variables for everything that you don't use anyway. What's the point of that. Even if you need to hardcode the use of eax for the string instructions, simply listing "eax" in the clobber list is immensely clearer than forcing it into a dummy output variable)).