Stuck at NSIS script - nsis

I've problem understanding NSIS script which I got from extracting with 7zip from some installer. I've several questions:
Does .onInit function executes before anything?
what is meaning of System::Call "* (&t256) p .r5 " call? as I know from the documentation is creates new structure but what is &t256 ?
As I know r0-r10 are registers, can I get value of r0 if r0 is pointer to some string, I need string, not pointer itself. Messagebox MB_OK "$r0" prints pointers
There is calls like *$1(&t255 .r0) I want to get value of $1.
Thank you

Yes, .onInit is the first part of a .NSI that is executed. (Internally it will read InstallDirRegKey as the first action before calling .onInit)
t is a string type, the same as TCHAR in C/C++. *(&t256)p.r5 is a buffer of 256 characters, enough to hold a filename. It allocates memory and stores the address in $5.
r0 is the system plug-in register syntax, it is the same as $0 in NSIS code, not $R0, that is a different register!
If $1 contains the address of a string in memory, *$1(&t255 .r0) will extract/place the first 255 characters of the string in $0.

Related

Emulating %defstr in earlier versions of NASM

Is there a way to emulate %defstr in NASM versions earlier than 2.03, preferably 0.99.06? More particularly, I want this macro to work:
%macro name 1
%defstr __namestr__ %1
%1: db __namestr__, 0
%endmacro
so that name hello would be equivalent to hello: db 'hello', 0. It already works in NASM 2.03 and later. I need it in a portable NASM include file, and requiring the user to upgrade NASM is not an option.
This doesn't work, it emits a literal %1 (2 bytes) + NUL.
%macro name 1
%1: db '%1', 0
%endif
NASM 0.99.06 .. NASM 2.02 documentation says that a workaround can be created using a multi-line macro (for converting tokens to a string literal), but it doesn't specify how. The full excerpt:
The `%!<env>' directive makes it possible to read the value of an
environment variable at assembly time. This could, for example, be
used to store the contents of an environment variable into a string,
which could be used at some other point in your code.
For example, suppose that you have an environment variable `FOO',
and you want the contents of `FOO' to be embedded in your program.
You could do that as follows:
%define FOO %!FOO
%define quote '
tmpstr db quote FOO quote
At the time of writing, this will generate an "unterminated string"
warning at the time of defining "quote", and it will add a space
before and after the string that is read in. I was unable to find a
simple workaround (although a workaround can be created using a
multi-line macro), so I believe that you will need to either learn
how to create more complex macros, or allow for the extra spaces if
you make use of this feature in that way.
The preprocessor macro %defstr is “smart” enough and escapes, for instance, any occurrence of string delimiter characters.
Therefore it’s different from a %define simply surrounding the argument with quotes.
However, in your specific case, since the first and only parameter to the name macro must also be suitable label, you do not have to worry about problematic characters.
Taking the excerpt from the documentation as inspiration and after having verified that %+ was already documented in 0.98.x, you can write something like:
%define quote '
%macro name 1
%1: db quote %+%1%+ quote, 0
%endmacro
I did only check this with NASM version 2.15.05, so no guarantee that this indeed works with 0.99.06.

Basic understanding of calling kernel functions in NSIS

In NSIS, I was going through some API which calls some functions of Windows.
For example:
Kernel32::SetEnvironmentVariable(t, t)i ("VAR1", "$R0").r0
Kernel32::GetLocaleInfo(i,i,t,i)i(2048,0x2,.r0,${NSIS_MAX_STRLEN})i
As I am a newbie, can anyone please explain what is happening here ? What is t , i , .ro etc. ?
I know that kernel32 is a DLL and SetEnvironmentVariable & GetLocaleInfo are the functions defined in this DLL.
The documentation will tell you what t and i are.
The basic syntax for System::Call is module::function(parameters)return. Parameters and return are optional and they both follow the same basic format: type input output. Type is not optional if you need input and/or output.
Parameters and return can be repeated multiple times, this is only useful when the function prototype exists as a define but you sometimes see this syntax on the NSIS Wiki as well. Kernel32::SetEnvironmentVariable(t, t)i ("VAR1", "$R0").r0 is exactly the same as Kernel32::SetEnvironmentVariable(t "VAR1", t "$R0")i.r0. When using a define it would look like this:
!define SetEnvironmentVariable "Kernel32::SetEnvironmentVariable(t, t)i"
System::Call '${SetEnvironmentVariable}("VAR1", "$R0").r0'
It is helpful if you know a language like C/C++ or Delphi when using the System plug-in because you need to understand the basic Windows types and how functions are typically used.
If for example you wanted to call the GetWindowsDirectory function you would first look at the function on MSDN:
UINT WINAPI GetWindowsDirectory(_Out_ LPTSTR lpBuffer, _In_ UINT uSize);
Translating this to NSIS gives you a initial skeleton of Kernel32::GetWindowsDirectory(t, i)i (WINAPI is the default calling convention). t maps to the Windows TCHAR* type and i is a 32-bit integer, the same as ULONG, LONG, DWORD, INT, UINT, INT32 and UINT32 in the Windows SDK.
The only missing piece is the input and output. The MSDN declaration is decorated with SAL annotations so it is easy to see which parameters are input and which are output.
A working example might look something like this:
System::Call 'Kernel32::GetWindowsDirectory(t .r1, i ${NSIS_MAX_STRLEN})i .r0'
DetailPrint "Return=$0 Output1=$1"
. can be used as a "nothing" placeholder when there is no input. In this case we use it twice. The return value never has input when using System::Call and we also have one output-only parameter.
r1 and r0 are aliases for the $1 and $0 NSIS registers and these aliases must be used when you need the output of something. The plain NSIS register can be used as input but then the variable expansion happens inside NSIS and not in the plug-in and this can cause issues with quotes in strings and is not really recommended if the string might contain quotes or legal System plug-in syntax. I would therefore recommend that your first example is rewritten as Kernel32::SetEnvironmentVariable(t "VAR1", t R0)i.r0.
In C your second example would look something like
char mybuf[1024];
GetLocaleInfo(MAKELCID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT), LOCALE_SLANGUAGE, mybuf, sizeof(mybuf));

Printing strings in LC-3 assembly language (super noob)

Super noob here. I'm doing a "hello world" type program in LC-3 assembly language and I simply don't know how to print more than one string to the console. I need 4 strings on separate lines that are my class, name, project and goodbye. Right now all I can seem to print in the class.
.ORIG x3000
LOOP LEA R0, CLASS
LD R1, NAME
LD R2, PROJECT
LD R3, GOODBYE
PUTS
HALT
CLASS .STRINGZ "CS101\n"
NAME .STRINGZ "JOHN\n"
...
.END
How would I get the other 3 to print? Thanks!
The Z in .STRINGZ means zero terminated. That is you have declared separate strings. If you want to print them all, you need to invoke PUTS multiple times. Alternatively, make it a single string with embedded newlines. Then you can print the whole thing in one go.

Whats this line mean? (system:call getfreediskex)

System::Call '${sysGetDiskFreeSpaceEx}(r0,.,,.r1)'
If i'm right, r0: directoryname, free bytes, number of bytes, number oof free bytes, but what actually means the r0,.,.,r1?
Thx for the help!
${...} is a define so when you want to know how some things work then the first thing you should do is to find out what the define does: !error "${sysGetDiskFreeSpaceEx}" will print !error: kernel32::GetDiskFreeSpaceEx(t, *l, *l, *l) i
In the System readme you will find this nugget:
PARAMS, RETURN and OPTIONS can be repeated many times in one Get/Call
line. When repeating, a lot can be omitted, and only what you wish to
change can be used. Type, source and/or destination can be omitted for
each parameter, even the return value. Options can be added or
removed. This allows you to define function prototypes and save on
some typing.
So ${sysGetDiskFreeSpaceEx} is a prototype that specifies the parameter count and types but it does not specify parameter source and destination.
What is the parameter syntax?
The parameters list is separated by commas. Each parameter is combined
of three values: type, source and destination. Type can be an integer,
a string, etc. Source, which is the source of the parameter value, can
be a NSIS register ($0, $1, $INSTDIR), the NSIS stack, a concrete
value (5, "test", etc.) or nothing (null). Destination, which is the
destination of the parameter value after the call returns, can be a
NSIS register, the NSIS stack or nothing which means no output is
required. Either one of source or destination can also be a dot (`.')
if it is not needed.
We can now expand the entire call !error 'System::Call "${sysGetDiskFreeSpaceEx}(r0,.,,.r1)"' and this gives us !error: System::Call 'kernel32::GetDiskFreeSpaceEx(t, *l, *l, *l) i(r0,.,,.r1)'
If we merge the repeated parameter definitions we get kernel32::GetDiskFreeSpaceEx(tr0, *l., *l, *l.r1)i.
So parameter 1 is a string (LPTSTR on MSDN) with the source r0 (NSIS register $0).
Parameter 2 and 3 have no source and no destination, only parameter 2 uses a . (dot) but the end result is the same; no input and no output. The only important part here is *l so the system plugin knows how large the parameter is.
The final parameter is a pointer (*) to a 64 bit number (l) with no input (.) and we request the output to be stored in $1 (r1).
The system plugin calls the native Windows API so it is often useful to look at MSDN to see what it has to say about the function you are calling.
Given that $0..$9 and $R0..$R9 are NSIS registers, the notation r0 -> r9 (resp. R10..R19 or also R0..R9) is used by the System plugin to specify the $0..$9 (resp. $R0..$R9) registers as a source and / or a destination with system API or other dll function calls.
Either one of source or destination can also be a dot (.) if it is not needed.
Look for the "Calling functions" and "Available sources and destinations" sections in the system plugin documentation.

String in Assembly

What does .string do in assembly?
In an inline asm call in c, I wrote
.string \"Hello World\"
1) Can somebody give me an overview of how .string works?
2) Somehow that value gets saved in %esi. Why?
3) How can I append a return carriage on the end? \n doesn't work
.string is an assembler directive in GAS similar to .long, .int, or .byte. All it does is create and initialize memory for you to use in your program. The .string directive will automatically null-terminate the string with [\0] for you. In this case, the assembler is allocating space for 14 characters in 14 contiguous bytes of memory. If you were to look at the memory, you would see this:
["][H][e][l][l][o][ ][W][o][r][l][d]["][\0]
Except in hexadecimal rather than characters. I'm not sure how or why %esi points to the string (it's either an assembler setting I'm not familiar with or has been set that way on a line of code you're not showing us). What it means is that %esi "points" to the first byte of the string - in this case the first ["]. You can use the %esi register to loop through the bytes using an offset (%esi + 5 would be [o]) or by incrementing the register itself.
To add a newline you might want to try \x0D\x0A instead of \n.
It just emits a sequence of characters into the appropriate code/data section. See this and this (they use .ascii, though).
Show us the code.
Try \\n or \12 or \xa.

Resources