The MASM Forum

General => The Workshop => Topic started by: aw27 on September 09, 2017, 01:44:37 AM

Title: Small .exes in C
Post by: aw27 on September 09, 2017, 01:44:37 AM
Some people say it is impossible to make smaller applications in C than in Assembly Language.
This is not totally true. Using as model the code from this message (http://masm32.com/board/index.php?topic=6524.msg69994#msg69994) I made a C .exe of the same size as the MASM one, i.e 3072 bytes. The output is the same, the difference is that the encrypted string is not in the middle of the code. That could have been done as well with inline asm, but I prefered to keep it all in C this time.
The compiler used was VS 2017 using the Windows SDK 7.1 toolset.
The code and .exe are attached.

Title: Re: Small .exes in C
Post by: hutch-- on September 09, 2017, 02:24:55 AM
I am taking unfair advantage of you here Jose, not only am I using MASM but I used Pelle's linker.

MASM the magnificent and modest at 1536 bytes.  :P

I forgot to free the allocated memory. Main should look like this.

main proc

    LOCAL ptxt:DWORD

    call mangled
    mov ptxt, eax
    invoke StdOut, ptxt
    free ptxt

    ret

main endp


Builds at the same size.
Title: Re: Small .exes in C
Post by: nidud on September 09, 2017, 03:20:49 AM
deleted
Title: Re: Small .exes in C
Post by: hutch-- on September 09, 2017, 03:45:25 AM
ust looking at the code, it appears that neither of you guys are decrypting the data, it looks like you have just stored the text data in numeric form.
Title: Re: Small .exes in C
Post by: aw27 on September 09, 2017, 04:14:14 AM
Quote from: hutch-- on September 09, 2017, 03:45:25 AM
Just looking at the code, it appears that neither of you guys are decrypting the data, it looks like you have just stored the text data in numeric form.

:biggrin:

Quote
1536 byte

If I use polink i get 1536 bytes as well.  :t
\masm32\bin\polink /SUBSYSTEM:console /NODEFAULTLIB main.obj \masm32\lib\msvcrt.lib

Sometimes, my antivirus bark when look at polink linked files.
Title: Re: Small .exes in C
Post by: Siekmanski on September 09, 2017, 04:25:33 AM
In the masm32 SDK there is this 1K example.
c:\masm32\examples\exampl07\masm1k\masm1k.exe
Title: Re: Small .exes in C
Post by: jj2007 on September 09, 2017, 05:14:39 AM
Sorry, I am a bit late, folks - the smally.vcxproj tried to open Visual Studio, and that took a while :greensml:

And the behemoth complains:Rebuild All: 0 succeeded, 1 failed, 0 skipped

No additional info why it fails - I assume it's because it's genuine Microsoft software :bgrin:

@nidud: fatal error A1000: cannot open file : alloc.inc

Re obfuscation, the reverse engineer should not have such an easy job imho:

Smally.exe:00D61011             ³.  B9 0030D600          mov ecx, offset 00D63000
00D61016             ³.  8D50 64              lea edx, [eax+64]
00D61019             ³>  8B39                 Úmov edi, [ecx]
00D6101B             ³.  33FE                 ³xor edi, esi
00D6101D             ³.  893A                 ³mov [edx], edi
00D6101F             ³.  8B31                 ³mov esi, [ecx]
00D61021             ³.  83C1 04              ³add ecx, 4
00D61024             ³.  83EA 04              ³sub edx, 4
00D61027             ³.  81F9 6830D600        ³cmp ecx, offset 00D63068
00D6102D             ³. 7C EA                Àjl short 00D61019
00D6102F             ³.  50                   push eax                          ; ³format
00D61030             ³.  FF15 0020D600        call near [<&msvcrt.printf>]      ; ÀMSVCRT.printf


ObfuscateString.exe:004011AA              .  E8 68000000          call 00401217                     ; ÀObfuscateString.00401217
004011AF              .  34 E5                xor al, E5
004011B1              .  11BB 51973FBB        adc [ebx+BB3F9751], edi
004011B7                 36                   db 36                             ; char '6'
004011B8                 FE                   db FE                             ; char 'þ'
004011B9                 51                   db 51                             ; char 'Q'
004011BA                 DE                   db DE                             ; char 'Þ'
004011BB                 53                   db 53                             ; char 'S'
004011BC                 DE                   db DE                             ; char 'Þ'
004011BD                 34                   db 34                             ; char '4'
004011BE                 B0                   db B0
004011BF                 25                   db 25                             ; char '%'
004011C0                 BB                   db BB
004011C1             Ú.  46                   inc esi
004011C2             À.  C3                   retn
...
00401217             Ú$  5A                   pop edx    ; here you land when using F7 - with F8 you'll never see this part ;-)
00401218             ³.  6A 1A                push 1A
0040121A             ³.  59                   pop ecx
0040121B             ³>  8B02                 Úmov eax, [edx]
0040121D             ³.  3342 FC              ³xor eax, [edx-4]
00401220             ³.  83C2 04              ³add edx, 4
00401223             ³.  50                   ³push eax
00401224             ³.  49                   ³dec ecx
00401225             ³. 75 F4                Àjnz short 0040121B
00401227             ³.  54                   push esp
00401228             ³.  6A 01                push 1
0040122A             ³.  6A 02                push 2
0040122C             ³.  E8 06130000          call 00402537


I like Erol's code. The Pelles C IDE opens in 3 seconds, it builds in 2 seconds, and it doesn't complain about any errors :t
Besides, the clear text becomes visible only when the whole loop is finished, that is even better than my version :t
Title: Re: Small .exes in C
Post by: Vortex on September 09, 2017, 05:29:09 AM
Hi aw27,

Nice example. Thanks. Source code built with Pelles C.

A small modification in your code to avoid problems with getchar :

The header file stdio.h supplied with Pelles C :

/* macro overrides */
#if !defined(__MT__) && !defined(_DLL)
#define getc(str)     ((str)->ptr < (str)->getend ? *(str)->ptr++ : (fgetc)(str))
#define getchar()     (__filetab[0]->ptr < __filetab[0]->getend ? *__filetab[0]->ptr++ : (fgetc)(__filetab[0]))


#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#undef getchar


Reference :

http://www.masmforum.com/board/index.php?PHPSESSID=786dd40408172108b65a5a36b09c88c0&topic=14078.0
Title: Re: Small .exes in C
Post by: aw27 on September 09, 2017, 03:38:53 PM
Nice tip Siekmanski. :t
Adding
#pragma comment(linker,"/merge:.rdata=.data")
#pragma comment(linker,"/merge:.data=.text")
Fixed base Address:YES and Randomized Base Address: NO under Linker Advanced

reduces the file linked with MS Link to 1024 bytes and the file linked with polink to 1024 bytes as well.

Thank you Vortex too.
Title: Re: Small .exes in C
Post by: hutch-- on September 09, 2017, 03:54:46 PM
What is being missed here is the MASM example stores 2 sequences of data that are XORRED together to produce the string. One in the code section, the other in the data section so to make a comparable example you need to add the code to do that otherwise you are not comparing the same thing.

The /MERGE option often drops the size by one 512 byte section but its not much use for any viable executable file.
Title: Re: Small .exes in C
Post by: aw27 on September 09, 2017, 04:26:31 PM
Quote from: hutch-- on September 09, 2017, 03:54:46 PM
What is being missed here is the MASM example stores 2 sequences of data that are XORRED together to produce the string. One in the code section, the other in the data section so to make a comparable example you need to add the code to do that otherwise you are not comparing the same thing.

The /MERGE option often drops the size by one 512 byte section but its not much use for any viable executable file.
The MASM example creates a DATA section which was not used in the code. But even merging sections I can not go under 1536 bytes both with link.exe and polink.exe.  :icon_confused:

The reason may be some overhead added by the SDK.
If I don't use the SDK I can indeed reach the 1024 bytes size.


.386
.model flat, stdcall
option casemap :None

includelib \masm32\lib\msvcrt.lib
getchar proto C
printf proto C :ptr, :vararg

STD_OUTPUT_HANDLE equ -11

.code
main proc C

call @F
@obs$ dd 0BB11E534h,0BB3F9751h,0DE51FE36h,0B034DE53h,0C346BB25h,0A6349B4Ah,0D214E92Fh,0B6668847h,09612E167h,0F17C880Ch,09011A820h,
0F165C944h,0D101AC20h,0B564CE4Dh,0D044AB39h,0B127D84Ch,0D745B76Ch,0B8319709h,0DC5EF429h,0B83F9C09h,0DD49F97Dh,
08E66911Eh,0FA13D93Eh,0D676B457h,0A256D139h,0CD76A578h
@@:
pop edx
mov ecx, sizeof @obs$/4
push 0
.Repeat
mov eax, [edx]
mov ebx, [edx-4]
xor eax, [edx-4]
add edx, 4
push eax
dec ecx
.Until Zero?
INVOKE printf, esp
INVOKE getchar

add esp, sizeof @obs$ +4
ret

main endp
end main

linked with POLINK as follows:
\masm32\bin\polink /MERGE:.rdata=.data /MERGE:.data=.text /SUBSYSTEM:console xor2.obj

Title: Re: Small .exes in C
Post by: hutch-- on September 09, 2017, 04:47:26 PM
Jose,

I think you have mis-understood what the code does. The code in the data section is loaded into the EDX register then XORRED against the address stored in ESI. This is how the string is decrypted and the result is returned in EAX.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

mangled proc

    LOCAL pMem  :DWORD

  ; --------------------------------------------------------
  ; Return value in EAX is the memory pointer to the result
  ; The data length is returned in ECX. Deallocate memory in
  ; EAX with the Windows API function GlobalFree() or the
  ; MASM32 macro "free".
  ; --------------------------------------------------------

    push ebx
    push esi
    push edi

    mov pMem, alloc(102)

    mov esi, pMem

    mov DWORD PTR [esi+52], 2701825359
    mov DWORD PTR [esi+32], 4160494258
    mov DWORD PTR [esi+68], 202942781
    mov DWORD PTR [esi+16], 4294820983
    mov DWORD PTR [esi+44], 4205567486
    mov DWORD PTR [esi+0],  4017705100
    mov DWORD PTR [esi+84], 3971489685
    mov DWORD PTR [esi+4],  3496616615
    mov DWORD PTR [esi+12], 2682706439
    mov DWORD PTR [esi+92], 3083553528
    mov DWORD PTR [esi+96], 555372704
    mov DWORD PTR [esi+76], 3809159684
    mov DWORD PTR [esi+24], 2440797704
    mov DWORD PTR [esi+60], 2520516412
    mov DWORD PTR [esi+36], 2923264119
    mov DWORD PTR [esi+8],  2102397535
    mov DWORD PTR [esi+72], 2337906632
    mov DWORD PTR [esi+56], 1913045396
    mov DWORD PTR [esi+88], 4275180973
    mov DWORD PTR [esi+80], 1300258737
    mov DWORD PTR [esi+64], 50501529
    mov BYTE PTR [esi+100], 216
    mov DWORD PTR [esi+28], 2224536879
    mov DWORD PTR [esi+20], 1926482737
    mov DWORD PTR [esi+48], 2526482862
    mov DWORD PTR [esi+40], 3701432909

    mov edi, 101
    or ebx, -1

  @@:
    add ebx, 1
    movzx edx, BYTE PTR [mangled_pad+ebx]
    xor [esi+ebx], dl
    sub edi, 1
    jnz @B

  ; -------------------------------------------------
  ; EAX is the memory pointer, ECX is the BYTE length
  ; -------------------------------------------------
    mov eax, pMem
    mov ecx, 101

    pop edi
    pop esi
    pop ebx

    ret

  .data
  mangled_pad \
    db 205,36,89,128,201,71,74,164,54,103,53,81,39,146,147,235
    db 20,172,210,172,69,174,165,23,40,246,26,245,15,222,248,224
    db 215,58,136,152,87,23,95,200,56,17,252,189,138,184,139,159
    db 195,115,242,242,43,240,110,129,240,160,114,19,16,39,81,247
    db 242,254,108,100,29,192,108,44,160,254,43,239,97,88,43,151
    db 222,127,242,40,227,122,202,159,200,53,183,144,159,35,165,210
    db 197,34,52,44,210
  .code

mangled endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
Title: Re: Small .exes in C
Post by: aw27 on September 09, 2017, 04:53:24 PM
@Hutch
I was always talking about the code in this message: http://masm32.com/board/index.php?topic=6524.msg69994#msg69994

I have not yet looked properly at your code. I will later. :t
Title: Re: Small .exes in C
Post by: jj2007 on September 09, 2017, 05:20:52 PM
Quote from: aw27 on September 09, 2017, 04:53:24 PM
@Hutch
I was always talking about the code in this message: http://masm32.com/board/index.php?topic=6524.msg69994#msg69994

You made some adjustments, what is their purpose?

        call @F
@obs$   dd 0BB11E534h,0BB3F9751h,0DE51FE36h,0B034DE53h,0C346BB25h,0A6349B4Ah,0D214E92Fh,0B6668847h,09612E167h,0F17C880Ch,09011A820h,
        0F165C944h,0D101AC20h,0B564CE4Dh,0D044AB39h,0B127D84Ch,0D745B76Ch,0B8319709h,0DC5EF429h,0B83F9C09h,0DD49F97Dh,
        08E66911Eh,0FA13D93Eh,0D676B457h,0A256D139h,0CD76A578h
@@:
        pop edx
        mov ecx, sizeof @obs$/4
        push 0
        .Repeat
                mov eax, [edx]
                mov ebx, [edx-4]
                xor eax, [edx-4]
                add edx, 4
                push eax
                dec ecx
        .Until Zero?
        INVOKE printf, esp

        add esp, sizeof @obs$ +4
Title: Re: Small .exes in C
Post by: aw27 on September 09, 2017, 07:01:18 PM
Quote from: jj2007 on September 09, 2017, 05:20:52 PM
Quote from: aw27 on September 09, 2017, 04:53:24 PM
@Hutch
I was always talking about the code in this message: http://masm32.com/board/index.php?topic=6524.msg69994#msg69994

You made some adjustments, what is their purpose?

        call @F
@obs$   dd 0BB11E534h,0BB3F9751h,0DE51FE36h,0B034DE53h,0C346BB25h,0A6349B4Ah,0D214E92Fh,0B6668847h,09612E167h,0F17C880Ch,09011A820h,
        0F165C944h,0D101AC20h,0B564CE4Dh,0D044AB39h,0B127D84Ch,0D745B76Ch,0B8319709h,0DC5EF429h,0B83F9C09h,0DD49F97Dh,
        08E66911Eh,0FA13D93Eh,0D676B457h,0A256D139h,0CD76A578h
@@:
        pop edx
        mov ecx, sizeof @obs$/4
        push 0
        .Repeat
                mov eax, [edx]
                mov ebx, [edx-4]
                xor eax, [edx-4]
                add edx, 4
                push eax
                dec ecx
        .Until Zero?
        INVOKE printf, esp

        add esp, sizeof @obs$ +4

The push 0 is to make sure the string will be null terminated. The other was just for debugging, I forgot to remove it.
Title: Re: Small .exes in C
Post by: jj2007 on September 09, 2017, 09:15:02 PM
Quote from: aw27 on September 09, 2017, 07:01:18 PMThe push 0 is to make sure the string will be null terminated.

No need for that, RichMasm takes care of that zero.
Title: Re: Small .exes in C
Post by: aw27 on September 10, 2017, 03:06:27 AM
Quote from: hutch-- on September 09, 2017, 04:47:26 PM
I think you have mis-understood what the code does
@hutch,
I was not aware of your mangle.exe and it looks good for the purpose. Of course, professional hackers, those individuals that have plenty of time and no life, are always able to bypass all defenses.
Title: Re: Small .exes in C
Post by: jj2007 on September 10, 2017, 03:14:17 AM
Just for fun, another one, generated by a RM beta. I am afraid it's not so small - the new limit is about 40,000 characters. "Source" attached, builds fine with qEditor and the old ML 6.14. Surprisingly, there are traces of French in the output - Google translate does strange things nowadays ::)

include \masm32\include\masm32rt.inc  ; pure Masm32

.code
start:
  push 5296
  call @F
  ...


To Olly, it looks Chinese, but it isn't:
00401010              .  E8 C0520000          call 004062D5                     ; ÀLeoWasHere.004062D5
00401015              .  18B6 0D9636B6        sbb [esi+B636960D], dh
0040101B              .  51                   push ecx
0040101C              .  B1 E6                mov cl, 0E6
0040101E              .  0A80 325D2A50        or al, [eax+502A5D32]
00401024              .  87EA                 xchg edx, ebp
00401026              .  FA                   cli
00401027              . E0 57                loopnz short 00401080
00401029              .  50                   push eax
0040102A              >  2A50 87              sub dl, [eax-79]
0040102D              . 70 FB                jo short 0040102A
0040102F              .  D157 A1              rcl dword ptr [edi-5F], 1
Title: Re: Small .exes in C
Post by: hutch-- on September 10, 2017, 11:39:11 AM
Jose,

> are always able to bypass all defenses.

This has always been the case but its a time factor that works for you. Something that is slow, complicated, tedious and highly error prone will beat 99% of them, if you slow up the talented remaining 1% for long enough they often will not bother. The real humour is the vast majority of software would not be worth of having, even if they paid you to use it.
Title: Re: Small .exes in C
Post by: aw27 on September 10, 2017, 04:00:11 PM
@hutch,
I agree. I have many stories with crackers, but the funniest one is this.
Someone told me that some software on my list has been cracked and gave me a link to a board of pirates and crackers where a guy was boasting the feat. I could not post on the site because registration depended on a recommendation from another member. However, the pompous alias of the cracker told me that I might be able to find him somewhere else. Indeed, I discovered that he was the owner of a website dedicated to development of chess engines. I send him a message on the forum of his site showing my appreciation for his efforts to promote the software.  :shock:
He said he would compensate me and place a marquee on the top of the main page of the website announcing my software :dazzled: and he did for a long time.  :t
Years later I decided to make that software free and he sent me the following email (tracking details disguised):

To: AW

From:
HisName
HisEmailAddress

Message:
Hello,
I remember you contacted me several years ago on my forum at
domain.com about googol+. I just wanted to say that I am
happy to see that you released it now as freeware. It has always been
in my collection of math software and is one of my favorite utilities.
Keep up the good work and I wish you all of the best in the future. :)


:biggrin:


Title: Re: Small .exes in C
Post by: Siekmanski on September 11, 2017, 01:31:57 AM
 :biggrin: