News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

.MODEL flat

Started by CCurl, October 29, 2015, 05:06:59 AM

Previous topic - Next topic

CCurl

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?

Vortex

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.

CCurl

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

hutch--

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.

nidud

#4
deleted

jj2007

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.

dedndave

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.msg50251#msg50251

CCurl

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.

jj2007

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.

dedndave

no problem - i just thought maybe you had forgotten the first thread - lol

CCurl

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.

jj2007

I advise you to post full code with headers, so that we can run it with a debugger.

dedndave

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:

CCurl

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.

sinsi

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.