The MASM Forum

General => The Campus => Topic started by: CCurl on October 29, 2015, 05:06:59 AM

Title: .MODEL flat
Post by: CCurl on October 29, 2015, 05:06:59 AM
Does this mean that all segments share the same space, and that the program's code and data are all together in one big happy segment?

If so, then assuming I have space set aside for it, it also means that I should be able to put new machine code in that space at run time, and then run it, right?
Title: Re: .MODEL flat
Post by: Vortex on October 29, 2015, 05:22:07 AM
Hi CCurl,

Yes, code and data are sharing the same space. From \masm32\help\asmintro.chm :
Quote

Flat memory Model

A program written in native 32 bit Windows format is created in what is called FLAT memory model which has a single segment that contains both code and data. The programs must be run on a 386 or higher processor.

Differing from earlier 16 bit code that used combined segment and offset addressing with a 64k segment limit, FLAT memory model works only in offsets and has a range of 4 gigabytes. This makes assembler easier to write and the code is generally a lot faster.

All segment registers are automatically set to the same value with this memory model and this means that segment / offset addressing must NOT be used in 32 bit programs that run in 32 bit Windows.
For programmers who have written code in DOS, a 32 bit Windows PE executable file is similar in some respects to a dos COM file, they have a single segment that can contain both code and data and they both work directly in offsets, neither use Segment / Offset addressing.

The defaults in flat-model programs are NEAR code addressing and NEAR data addressing within the range of 4 gigabytes.

The FS and GS segment registers are not normally used in application programs but are used in some instances by the operating system.

You must be careful while modifying your executable ( = put new machine code at run time ) This can trigger the antivirus software and this type of coding is more difficult to maintain.
Title: Re: .MODEL flat
Post by: CCurl on October 29, 2015, 07:05:04 AM
So I did a little test ...

I created a codeBuffer BYTE 100 (0) and filled it in with some simple machine code to MOV a number (0) into EDX (ba 00 00 00 00), with a RET (c3) at the end.

Then I loaded the address of that buffer into EBX and executed CALL EBX (ff d3).

0xC0000005: Access violation.

sigh
Title: Re: .MODEL flat
Post by: hutch-- on October 29, 2015, 07:20:15 AM
Keep in mind that as of Win XP, Microsoft introduced DEP (Data Execution Prevention) to restrict certain types of exploits. You need to allocate memory and specify that it is read/write/execute to do what you are after.
Title: Re: .MODEL flat
Post by: nidud on October 29, 2015, 07:24:40 AM
deleted
Title: Re: .MODEL flat
Post by: jj2007 on October 29, 2015, 07:52:09 AM
This works on Win7-64:
include \masm32\include\masm32rt.inc

.code
destination db "Surprise.." ; the MessageBox code will go here
start:
mov edi, offset destination
push edi
mov esi, offset MyMB
.Repeat
movsb
.Until esi>=MyMB_end
pop edi
int 3   ; for the debugger
call edi
  exit

MyMB:
  mov esi, MessageBox
  push MB_OK
  push chr$("Copied:")
  push chr$("Hello World")
  push 0
  call esi ; MsgBox 0, "Hello World", "Copied:", MB_OK
  retn
MyMB_end:
end start


The linker commandline must contain /SECTION:.text,rwe

In case you are using RichMasm, insert this line under "end start", then hit F6:
OPT_DebugL   /SECTION:.text,RWE

Otherwise, use a batch file.

P.S.: Before & after:
destination                   53                         db 53                                ;  CHAR 'S'
00401001                      75                         db 75                                ;  CHAR 'u'
00401002                      72                         db 72                                ;  CHAR 'r'
00401003                      70                         db 70                                ;  CHAR 'p'
00401004                      72                         db 72                                ;  CHAR 'r'
00401005                      69                         db 69                                ;  CHAR 'i'
00401006                      73                         db 73                                ;  CHAR 's'
00401007                      65                         db 65                                ;  CHAR 'e'
00401008                      2E                         db 2E                                ;  CHAR '.'
00401009                      2E                         db 2E                                ;  CHAR '.'
<ModuleEntryPoint>        /$  BF 00104000                mov edi, destination                 ;  ASCII "Surprise..¿"
0040100F                  |.  57                         push edi
00401010                  |.  BE 28104000                mov esi, 00401028
00401015                  |>  A4                         movsb
00401016                  |.  81FE 3E104000              cmp esi, MessageBoxA                 ;  jmp to user32.MessageBoxA
0040101C                  |.^ 72 F7                      jb short 00401015
0040101E                  |.  5F                         pop edi
0040101F                  |.  FFD7                       call near edi


destination                 BE 40104000                  mov esi, MessageBoxA                 ; jmp to user32.MessageBoxA
00401005                    6A 00                        push 0
00401007                    68 00304000                  push offset ??0019                   ; ASCII "Copied:"
0040100C                    68 08304000                  push offset ??001A                   ; ASCII "Hello World"
00401011                    6A 00                        push 0
00401013                    FFD6                         call near esi
00401015                    C3                           retn
00401016                    81FE 3F104000                cmp esi, 0040103F
0040101C                  ^ 72 F7                        jb short 00401015
0040101E                    5F                           pop edi
0040101F                    CC                           int3
00401020                    FFD7                         call near edi                        ; NewMasm3.destination
00401022                    6A 00                        push 0
00401024                    E8 1D000000                  call ExitProcess                     ; jmp to kernel32.ExitProcess
00401029                    BE 40104000                  mov esi, MessageBoxA                 ; jmp to user32.MessageBoxA
0040102E                    6A 00                        push 0
00401030                    68 00304000                  push offset ??0019                   ; ASCII "Copied:"
00401035                    68 08304000                  push offset ??001A                   ; ASCII "Hello World"
0040103A                    6A 00                        push 0
0040103C                    FFD6                         call near esi
MessageBoxA                 C3                           retn


You might have a closer look at address 00401015 :biggrin:

An even weirder example is attached. Open it in Olly, hit F8 until VirtualProtect is passed, then continue with F7 (single step). From time to time, select a few lines and hit Ctrl A to force Olly to update the disassembly.
Title: Re: .MODEL flat
Post by: dedndave on October 29, 2015, 12:44:40 PM
again, i would avoid special build command lines

use VirtualProtect - we covered this in one of your first threads....

http://masm32.com/board/index.php?topic=4664.msg50217#msg50217 (http://masm32.com/board/index.php?topic=4664.msg50217#msg50217)

http://masm32.com/board/index.php?topic=4664.msg50251#msg50251 (http://masm32.com/board/index.php?topic=4664.msg50251#msg50251)
Title: Re: .MODEL flat
Post by: CCurl on October 29, 2015, 03:28:29 PM
Sorry about seemingly asking the same question again, but it felt a little different to me ... in the other thread, the question was more centered around putting machine code into dynamically allocated memory, whereas dynamic memory allocation wasn't part of this question. But at the end of the day, is sounds like the issue, and the way to address it, are the same.

I've only been at this a couple of weeks, so I'm still green about alot of things. Thanks for your patience.
Title: Re: .MODEL flat
Post by: jj2007 on October 29, 2015, 07:01:43 PM
Quote from: dedndave on October 29, 2015, 12:44:40 PM
again, i would avoid special build command lines

use VirtualProtect

Thats' what I did - no special command line needed:
Quote from: jj2007 on October 29, 2015, 07:52:09 AMAn even weirder example is attached. Open it in Olly, hit F8 until VirtualProtect is passed, then continue with F7 (single step). From time to time, select a few lines and hit Ctrl A to force Olly to update the disassembly.
Title: Re: .MODEL flat
Post by: dedndave on October 30, 2015, 01:21:15 AM
no problem - i just thought maybe you had forgotten the first thread - lol
Title: Re: .MODEL flat
Post by: CCurl on October 30, 2015, 04:03:08 PM
OK ... so ...

memorySize EQU 1024*1024*8

call GetProcessHeap
invoke HeapAlloc, eax, 0, memorySize
mov ebx, eax
invoke VirtualProtect, ebx, memorySize, PAGE_EXECUTE_READWRITE, edx

GetProcessHeap sets EAX to a non-ZERO value, presumably the heap handle.
HeapAlloc sets EAX to a different non-ZERO value, presumably the pointer to the memory it allocated.
VirtualProtect sets EAX (and EDX) to ZERO, which the documentation makes me think it probably failed.
- it also sets ECX to an apparently random number.

Please advise.
Title: Re: .MODEL flat
Post by: jj2007 on October 30, 2015, 05:56:12 PM
I advise you to post full code with headers, so that we can run it with a debugger.
Title: Re: .MODEL flat
Post by: dedndave on October 30, 2015, 10:33:04 PM
there are a few points here, to be aware of

call GetProcessHeap
invoke HeapAlloc, eax, 0, memorySize
mov ebx, eax
invoke VirtualProtect, ebx, memorySize, PAGE_EXECUTE_READWRITE, edx


first, when you call GetProcessHeap, save the results for later
i generally do this as part of program initializaion (i use a global dword labeled hHeap, in the .DATA? section)
even if you don't allocate other blocks, you will need it to free the block   :P

second, is the last argument for the VirtualProtect call
if you want to save the previous attribute for the memory block, it should be a pointer to the variable that receives it
otherwise, it should be NULL (NULL EQU 0 is in windows.inc)
the contents of EDX at that time are undefined

i don't really see a need for it, as i don't see a rule that says it has to be restored prior to freeing the block

finally, the use of the EBX register is a little unknown for us - we don't know the context of the code
this is why Jochen mentioned posting the entire code, so we can get the context
if it's inside a PROC, where EBX has been preserved, it's ok
if it's in the main procedure, it's ok

as an added note, i assume you save the block address in a global   :biggrin:
Title: Re: .MODEL flat
Post by: CCurl on October 31, 2015, 12:13:20 AM
Unfortunately, I did it last night at home, and I am at work now.

I just tried installing MASM on my work PC, and it is giving me that "You appeared to have cancelled the installation." message ... the other thread I just started. I was going to re-do it here at work and post the entire ASM file, but if I can't get MASM to install, I'm kind of stuck.

But that is essentially the entire contents of the program, save the call to ExitProcess. I made a totally barebones project to try out the calls, and that is all there is in the main proc.
Title: Re: .MODEL flat
Post by: sinsi on October 31, 2015, 12:52:41 AM
HeapAlloc has a much lower granularity (8 bytes?) than VirtualAlloc (4K page) but using VirtualProtect will change the attributes of a whole page, not just a small range within a page. The remarks for VirtualProtect warn against using HeapAlloc.
QuoteIt is best to avoid using VirtualProtect to change page protections on memory blocks allocated by GlobalAlloc, HeapAlloc, or LocalAlloc, because multiple memory blocks can exist on a single page. The heap manager assumes that all pages in the heap grant at least read and write access.

Something else to look out for
QuoteWhen protecting a region that will be executable, the calling program bears responsibility for ensuring cache coherency via an appropriate call to FlushInstructionCache once the code has been set in place. Otherwise attempts to execute code out of the newly executable region may produce unpredictable results.
Title: Re: .MODEL flat
Post by: CCurl on October 31, 2015, 01:54:25 AM
I was able to get something to build and run without installing MASM.

In this, VirtualAlloc returns EAX=0, so of course VirtualProtect will also not be successful.

; TEST program

; ---------------------------------------------------------------------------------------------------------
.686P
.model flat, stdcall
.stack 4096

; ---------------------------------------------------------------------------------------------------------
; Constants

memorySize EQU 1024*8

PAGE_READWRITE                  EQU 0004h
PAGE_EXECUTE                       EQU 0010h
PAGE_EXECUTE_READWRITE EQU 0040h

MEM_COMMIT                         EQU 010000h

; ---------------------------------------------------------------------------------------------------------
.data

hHeap DWORD ?
theMem DWORD ?

; ---------------------------------------------------------------------------------------------------------
.code

ExitProcess PROTO, dwExitCode:dword

GetProcessHeap PROTO    ; Get the current process heap handle

HeapAlloc PROTO,
hHeap:DWORD, ; handle to private heap block
dwFlags:DWORD, ; heap allocation control flags
dwBytes:DWORD ; number of bytes to allocate

HeapFree PROTO,
hHeap:DWORD, ; handle to heap with memory block
dwFlags:DWORD, ; heap free options
lpMem:DWORD ; pointer to block to be freed

VirtualProtect PROTO,
pMem:DWORD, ; pointer to the memory
dwSize:DWORD, ; size of area to protect
fNewProtect:DWORD, ; new protection
pOldProtect:DWORD ; pointer to storage for old protection value

VirtualAlloc PROTO,
pMem:DWORD, ; optional, NULL lets the system figure it out
dwSize:DWORD, ; requested size
fAllocType:DWORD, ; allocation type
fProtect:DWORD ; protection flags


; ---------------------------------------------------------------------------------------------------------
main proc

; call GetProcessHeap
; mov hHeap, eax
; invoke HeapAlloc, hHeap, 0, memorySize
; invoke HeapFree, hHeap, 0, theMem

invoke VirtualAlloc, 0, memorySize, MEM_COMMIT, PAGE_READWRITE
mov theMem, eax
invoke VirtualProtect, theMem, memorySize, PAGE_EXECUTE, 0

invoke ExitProcess,0

main endp
end main

; ---------------------------------------------------------------------------------------------------------
Title: Re: .MODEL flat
Post by: dedndave on October 31, 2015, 02:17:49 AM
when you set the attribute for VirtualProtect, use PAGE_EXECUTE_READWRITE so that you can write the code in there

PAGE_EXECUTE_READWRITE EQU 40h

VirtualAlloc will probably handle that attribute constant, so that you don't have to use VirtualProtect

also - we typically list PROTO's first in the source - they don't need to be in an opened section
Title: Re: .MODEL flat
Post by: CCurl on October 31, 2015, 03:05:05 AM
New ASM file ... do you get a value back in EAX from your VirtualAlloc call? Mine comes back with ZERO.

; TEST program

; ---------------------------------------------------------------------------------------------------------
.686P
.model flat, stdcall
.stack 4096

; ---------------------------------------------------------------------------------------------------------
ExitProcess PROTO,
dwExitCode:DWORD

GetProcessHeap PROTO    ; Get the current process heap handle

HeapAlloc PROTO,
hHeap:DWORD, ; handle to private heap block
dwFlags:DWORD, ; heap allocation control flags
dwBytes:DWORD ; number of bytes to allocate

HeapFree PROTO,
hHeap:DWORD, ; handle to heap with memory block
dwFlags:DWORD, ; heap free options
lpMem:DWORD ; pointer to block to be freed

VirtualProtect PROTO,
pMem:DWORD, ; pointer to the memory
dwSize:DWORD, ; size of area to protect
fNewProtect:DWORD, ; new protection
pOldProtect:DWORD ; pointer to storage for old protection value

VirtualAlloc PROTO,
pMem:DWORD, ; optional, NULL lets the system figure it out
dwSize:DWORD, ; requested size
fAllocType:DWORD, ; allocation type
fProtect:DWORD ; protection flags

; ---------------------------------------------------------------------------------------------------------
; Constants

memorySize EQU 1024*8

PAGE_READWRITE EQU 0004h
PAGE_EXECUTE EQU 0010h
PAGE_EXECUTE_READWRITE EQU 0040h

MEM_COMMIT EQU 010000h

; ---------------------------------------------------------------------------------------------------------
.data

hHeap DWORD ?
theMem DWORD ?

; ---------------------------------------------------------------------------------------------------------
.code

main proc

; call GetProcessHeap
; mov hHeap, eax
; invoke HeapAlloc, hHeap, 0, memorySize
; invoke HeapFree, hHeap, 0, theMem

invoke VirtualAlloc, 0, memorySize, MEM_COMMIT, PAGE_EXECUTE_READWRITE
mov theMem, eax
invoke VirtualProtect, theMem, memorySize, PAGE_EXECUTE_READWRITE, 0

invoke ExitProcess,0

main endp
end main

; ---------------------------------------------------------------------------------------------------------

Title: Re: .MODEL flat
Post by: dedndave on October 31, 2015, 03:09:45 AM
VirtualAlloc returns the address of the allocated block
if it returns 0, it means there is an error; call GetLastError to get the error code

https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887%28v=vs.85%29.aspx (https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887%28v=vs.85%29.aspx)
Title: Re: .MODEL flat
Post by: dedndave on October 31, 2015, 03:11:41 AM
QuoteTo reserve and commit pages in one step, call VirtualAlloc with MEM_COMMIT | MEM_RESERVE.

Attempting to commit a specific address range by specifying MEM_COMMIT without MEM_RESERVE and a non-NULL lpAddress fails unless the entire range has already been reserved. The resulting error code is ERROR_INVALID_ADDRESS.

in ASM, we use the OR operator
MEM_COMMIT or MEM_RESERVE
Title: Re: .MODEL flat
Post by: dedndave on October 31, 2015, 03:14:03 AM
by the way, 8KB allocation is very small
you could put that much (and more) in the .DATA? section, easily
Title: Re: .MODEL flat
Post by: CCurl on October 31, 2015, 03:18:35 AM
Whoops ... one too many ZEROs on the MEM_COMMIT constant. Now I get a non-ZERO number back from VirtualAlloc.

Yeah, 8K is just for the test, trying 8MB now.
Title: Re: .MODEL flat
Post by: CCurl on October 31, 2015, 03:46:27 AM
It WORKS!!!

; TEST program

; ---------------------------------------------------------------------------------------------------------
.686P
.model flat, stdcall
.stack 4096

; ---------------------------------------------------------------------------------------------------------
ExitProcess PROTO,
dwExitCode:DWORD

GetLastError PROTO

VirtualAlloc PROTO,
pMem:DWORD, ; optional, NULL lets the system figure it out
dwSize:DWORD, ; requested size
fAllocType:DWORD, ; allocation type
fProtect:DWORD ; protection flags

; ---------------------------------------------------------------------------------------------------------
; Constants

memorySize EQU 1024*1024*8

PAGE_READWRITE EQU 0004h
PAGE_EXECUTE EQU 0010h
PAGE_EXECUTE_READWRITE EQU 0040h

MEM_COMMIT EQU 01000h
MEM_RESERVE EQU 02000h
; ---------------------------------------------------------------------------------------------------------
.data

hHeap DWORD ?
theMem DWORD ?

; ---------------------------------------------------------------------------------------------------------
.code

main proc

invoke VirtualAlloc, 0, memorySize, MEM_COMMIT or MEM_RESERVE, PAGE_EXECUTE_READWRITE
mov theMem, eax
test eax, eax
jnz doTest
call GetLastError
jmp allDone

doTest:
mov ebp, theMem
inc ebp
mov byte ptr [ebp], 00bah
mov DWORD ptr [ebp][1], 11223344h
mov byte ptr [ebp][5], 00c3h
call ebp
; EDX should get 11223344h in it

allDone:
invoke ExitProcess,0
ret

main endp
end main

; ---------------------------------------------------------------------------------------------------------