flat assembler
Message board for the users of flat assembler.
![]() |
Author |
|
AsmGuru62 25 Sep 2025, 16:05
It looks like you need to call a function which pointer was returned by GetProcAddress:
Code: @@: invoke GetProcAddress,eax,GetCurrentThreadStackLimits_s cmp eax,0 je @f mov [pfn_GetLimits],eax invoke pfn_GetLimits,StackLow,StackHigh mov eax, 0 ret I was not able to test it in debugger, only part of code is provided, no variables like 'StackLow' ... etc. |
|||
![]() |
|
mns 26 Sep 2025, 18:14
Thank you AsmGuru62 for your kind response. I have attached full .asm file.
Here I want to call my "getStackSize" function (procedure) at WM_CREATE (wmcreate in the file). "getStackSize" will first call 'GetModuleHandle' for the "kernel32.dll", then using returned handle, program will call 'GetProcAddress' for the 'GetCurrentThreadStackLimits' (a win32 API which is available only from windows 8 ) If it is not in current "kernel32.dll" (eax=0), I will get the stack limits from FS register(which is not a reliable way for newer windows versions). if eax = not 0, that API is available, So I will call that API for the stack limits. My problem is, in windows 7 program assembled without problem, when try to run, It gives a error saying 'The procedure entry point GetCurrentThreadStackLimits could not be located in the dynamic link library KERNEL32.DLL' As I said earlier 'GetCurrentThreadStackLimits' API will not be called in windows 7 since GetProcAddress will return 0, so ideally this error msg should not have shown. ![]()
|
|||||||||||
![]() |
|
macomics 26 Sep 2025, 20:21
mns wrote: My problem is, in windows 7 program assembled without problem, when try to run, It gives a error saying 'The procedure entry point GetCurrentThreadStackLimits could not be located in the dynamic link library KERNEL32.DLL' You have already been pointed out the solution to the problem. You are currently using two import mechanisms for the GetCurrentThreadStackLimits function. Dynamic import via GetModuleHandle/GetProcAddress and static import via the name of GetCurrentThreadStackLimits function in the import section of your exe file. Dynamic import allows you to check for a function in the library and call it if necessary, but static import does not. Due to the static import of this function, your error occurs when loading the exe into memory on Windows 7. As mentioned above (AsmGuru62), you just need to call the function using the pointer obtained from GetProcAddress instead of calling it by name. Code: .data myGetCurrentThreadStackLimits dd ? .code ;------------------------------getStackSize-------------------------------------------------- proc getStackSize stdcall uses ebx esi edi ;call GetModuleHandle for "kernel32.dll" ;Call GetProcAddress to see if GetCurrentThreadStackLimits exists. ;If not direct limits via fs register(Thread Environment Block -TEB) ;if yes call GetCurrentThreadStackLimits invoke GetModuleHandle, kernel32_s cmp eax, 0 jne @f mov eax, -1 ret @@: invoke GetProcAddress,eax,GetCurrentThreadStackLimits_s cmp eax,0 je @f mov [myGetCurrentThreadStackLimits], eax invoke myGetCurrentThreadStackLimits,StackLow,StackHigh mov eax, 0 ret @@: ;if pre windows 8 OS------------------- push dword[fs:04h] pop [StackHigh] push dword[fs:08h] pop [StackLow] mov eax, 0 ret endp ;---------------------------------------------------------------------------------------------- |
|||
![]() |
|
bitRAKE 26 Sep 2025, 22:33
Code: ; Although undocumented, ALL known versions of have the exact same form: struct NT_TIB ExceptionList PTR ? ;*EXCEPTION_REGISTRATION_RECORD StackBase PTR ? ;*VOID StackLimit PTR ? ;*VOID SubSystemTib PTR ? ;*VOID union FiberData PTR ? ;*VOID Version dd ? ; u32 end union ArbitraryUserPointer PTR ? ;*VOID Self PTR ? ;*NT_TIB end struct assert sizeof NT_TIB = 7 * sizeof PTR ; 28/56 _________________ ¯\(°_o)/¯ AI may [not] have aided with the above reply. |
|||
![]() |
|
mns 27 Sep 2025, 06:38
Thank you very much macomics for the response and explanation.
And bitRAKE thank you for your response too. Microsoft site says TEB/TIB structures may be altered in future versions of Windows, so doesn't recommend using them directly.("https://learn.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-teb"). |
|||
![]() |
|
AsmGuru62 27 Sep 2025, 12:40
I am curious to know how are these values (StackHigh, StackLow) to be used in the code?
In the Remarks section for GetCurrentThreadStackLimits Microsoft mentions that this function is used to verify if a current stack pointer is within those limits. I find it strange, I mean, the only thing affecting stack pointer is how deep is level of your leaf functions is and how many local variables in each function your own code is allocating. So, your own code will define if somehow stack pointer would go out of range. Of course, there is a case of a recursive function calls, like sorting code. And, of course, if you are invoking Windows API, these API functions may have its own local variables. In my opinion, the large enough stack can be defined in FASM source code. In the posted code, there is no definition for stack. It means that stack = 1Mb of room with 4Kb committed. You can use the below statement to declare a good stack of 2Mb for both reserved and committed room: Code: format PE GUI 4.0 entry start stack 200000h, 200000h ; <--- 2Mb of stack room 2Mb stack should be enough for everyone! ![]() |
|||
![]() |
|
mns 01 Oct 2025, 14:14
Thank you very much AsmGuru62 (and I am sorry for the delay in response).
I am trying to make memory safe custom string concatenate function (actually created). Output of the function(destination) always in the heap memory. First Input (address of first string) will be checked for whether it is in stack or static space or heap (for that I need heap boundaries). For stack or static or heap(created out side function) strings, new destination will be created in the heap. For heap strings created previous call to the function, only reallocation done. Also there will be a array of memory addresses created by the function. which will be used to free everything when program closes. If you are interested I can share the source(mind you I am not a professional or advance programmer so there will be lot of errors, but it works). Thank you. |
|||
![]() |
|
Core i7 01 Oct 2025, 17:04
I once analyzed the Windows stack and found the following data.
By default, the system allocates 8 KB of stack space, after which a PAGE_GUARD exception occurs, and the system allocates another 4 KB page. This continues until a STACK_OVERFLOW exception is thrown, which means the limit is finally reached. At this point, the system kills the application without warning. On my Windows 7, I get a limit of not 1 MB, but only 256 KB, or 64 pages. This is easy to verify by setting your SEH handler to STACK_OVERFLOW=0xC00000FD. Here's an example I tested on Win7 x32, although it can be adapted for Win10 x64: Code: format pe console include 'win32ax.inc' entry start ;stack 200000h, 200000h ;//------- .data capt db 13,10,' STACK OVER-FLOW v0.1' db 13,10,' ********************' db 13,10,' Stack Base: 0x%X' ,10 db 13,10,' Allocate Address' db 13,10,' -------------------',0 limit db 13,10,' Page: %02d 0x%X' ,0 over db 13,10,' ------------------------------' db 13,10,' == Exception Stack_OverFlow ==' db 13,10,' System stack reserve = %d Kb',0 count dd 0 ;// PageGuard alloc counter frmt db '%s',0 buff db 0 ;//------- .code start: ;// Set SEH to 'StackOverflow' push @trap push dword[fs:0] mov [fs:0],esp mov eax,[fs:04] ;// EAX = TEB --> StackBase cinvoke printf,capt,eax ;// Main ====================== mov eax,[fs:08] ;// EAX = TEB --> StackLimit @cycle: push 'DEAD' ;// fill stack cmp [fs:08],eax je @cycle mov ebp,esp ;// PAGE_GUARD exception add ebp,4 inc [count] cinvoke printf,limit,[count],ebp mov eax,[fs:08] ;// EAX = new limit jmp @cycle ;// wait 'StackOverflow' ;//============================= @exit: cinvoke _getch cinvoke exit,0 ;//=== 'StackOverflow' handler @trap: mov esi,[esp+12] ;// ESI = CONTEXT struct mov eax,@exit mov [esi+0xb8],eax ;// 0xb8 = change EIP! mov eax,[count] mov ebx,4096 ;// EBX = Page size mul ebx ;// EAX = Alloc size add eax,4096*2 ;// add COMMIT page shr eax,10 ;// Byte to Mbyte cinvoke printf,over,eax xor eax,eax ret ;//------- section '.idata' import data readable library msvcrt,'msvcrt.dll' import msvcrt, printf,'printf',_getch,'_getch',exit,'exit' |
|||
![]() |
|
bitRAKE 02 Oct 2025, 05:40
msvcrt.dll has it's own exception handlers and a stack overflow has the stack in a damaged state (no guard page). See SetThreadStackGuarantee.
One way to get MSVCRT to stay out the way is just to touch the stack. This will repair the stack and report the correct size (minus the guard page). It's important to note that the overflow exception happens before the last page - to insure the overflow guarantee is met. Another major note would be that potentially no guard page exists if commit/reserve are the same! Code: format pe console include 'win32ax.inc' entry start ;stack 0x40000, 0x40000 ; results in 1MB reserve ;stack 0x10_0000, 0x10_0000 ; results guard page! ; Note: potentially no guard page if commit/reserve are the same. stack 0x20_0000, 0x20_0000 ; results in no guard page! .data capt db 13,10,' STACK OVER-FLOW v0.2' db 13,10,' ********************' db 13,10,' Base: 0x%X',10 db 13,10,' Allocate Address' db 13,10,' -------------------',0 limit db 13,10,' Page: %02d 0x%X' ,0 over db 13,10,' ------------------------------' db 13,10,' == Exception Stack_OverFlow ==' db 13,10,' System stack reserve = %d Kb',0 under db 13,10,' == Exception Access Violation ==' db 13,10,' System stack = %d Kb',0 count dd 0 ; We touch the stack without modify ESP to insure MSVCRT functions always have ; sufficent stack. .code start: cinvoke printf,capt,[fs:04] push stack_handler push [fs:0] mov [fs:0], esp @outer: mov eax,[fs:08] or ecx, -1 @cycle: test byte[eax+ecx], -1 dec ecx cmp [fs:08], eax je @cycle inc [count] cinvoke printf,limit,[count],[fs:08] jmp @outer @exit1: lea ecx, [under] mov eax, [fs:04] sub eax, [fs:08] jmp @F @exit0: lea ecx, [over] pop [fs:0] pop eax imul eax, [count], 4096 @@: shr eax, 10 cinvoke printf,ecx,eax cinvoke _getch cinvoke exit,0 stack_handler: mov eax, [esp+4] ; EXCEPTION_RECORD* mov ecx, [esp+12] ; CONTEXT* cmp dword [eax], 0xC0000005 ; EXCEPTION_ACCESS_VIOLATION jz .vila cmp dword [eax], 0xC00000FD ; EXCEPTION_STACK_OVERFLOW jz .ovfl @@: mov eax, 1 ; EXCEPTION_CONTINUE_SEARCH retn ; An access violation can occur below the stack bottom if there is no guard ; page. The loader doesn't create the guard page in some cases. *RARE* .vila: cmp dword [ecx+0xB8], @cycle jnz @B mov dword [ecx+0xB8], @exit1 xor eax, eax ; EXCEPTION_CONTINUE_EXECUTION retn .ovfl: cmp dword [ecx+0xB8], @cycle jnz @F mov dword [ecx+0xB8], @exit0 @@: call [_resetstkoflw] xor eax, eax ; EXCEPTION_CONTINUE_EXECUTION retn section '.idata' import data readable library msvcrt,'msvcrt.dll' import msvcrt,\ _getch,'_getch',\ _resetstkoflw,'_resetstkoflw',\ exit,'exit',\ printf,'printf' Last edited by bitRAKE on 02 Oct 2025, 19:27; edited 1 time in total |
|||
![]() |
|
AsmGuru62 02 Oct 2025, 15:45
mns, thanks for the explanation.
So, you are building a kind of string library, where text can be stored, concatenated, etc. I once did that, but all strings were on heap. When a new string was created, it was allocated in 64 characters pieces, so there was room for concatenation. Say, you need to make a new string "HELLO", you will get 64 characters on heap and then copy "HELLO" into it. In case, you wish to append ", WORLD!" to it --- there will be no re-allocation. I did not use stack, however, I think it is an unnecessary complication. Every one of my strings were represented by the structure: Code: struct TString Length dw ? ; # of UNICODE characters until 0x0000 is placed Room dw ? ; # of UNICODE characters after 'Flags' (including 0x0000) Flags dw ? ; Some bits on what type of string is it ; ; UNICODE buffer follows here... ; ends I could access the text buffer with a simple macro: Code: macro StrGetBuf r32_TextBuf, r32_TString { lea r32_TextBuf, [r32_TString + sizeof.TString] } To concatenate two TString objects --- fast operation if no re-allocation needed. Because both lengths are known, no need to count characters until 0x0000. |
|||
![]() |
|
mns 04 Oct 2025, 09:20
AsmGuru62 Thank you very much for the valuable Insight.
|
|||
![]() |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.