Thread: Real pixel coding

  1. #1
    Registered User
    Join Date
    Apr 2010
    Posts
    50

    Real pixel coding

    Hi.

    I know that actually is not a C coding thread but i didn't know where to post it.

    I found this interesting article on the net followed by a video showing a method for pixel coding. Maybe some of you already know this technique.

    Here is the link.

    How this guy choose the pallet color to use ?
    Which logic connects the colors with the executable code ?
    I did it with random colors and didn't work for example.

  2. #2
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by netpumber View Post
    How this guy choose the pallet color to use ?
    Which logic connects the colors with the executable code ?
    The raw format mentioned is very simple: the file is 3*width*height bytes long, no header or anything. Each triplet of bytes describes the color of a pixel, first byte being the red component (0 to 255), second the green, and third the blue. The 9*9 image therefore corresponds to 3*9*9 = 243 byte file.

    The COM format mentioned is the simplest executable format Windows supports (see COM file Wikipedia article for details). It is limited in size, but only contains executable code (and possibly initialized data in the same memory area).

    The tunnel effect is a very old demo coders trick. (See here for an example describing it in detail.) It is much easier to implement than one would think.

    The disassembly shown in the video starts with
    Code:
    0100 B7 10    MOV BH,10
    0102 B4 4A    MOV AH,4A
    0104 CD 21    INT 21H
    which tells us the color of the first pixel is #B710B4 and the second pixel #4ACD21. (COM executables always start at address 0100.)
    However, the image provided by the author starts with color #B100B5, which already tells us he is lying; the image provided has nothing to do with the demo.

    In fact, the actual code used is somewhat modified tunnel demo by iq, released in 2002, and is 224 bytes long. (I think the modifications help it run correctly on current Windows versions, but not being a Windows user, I cannot verify this.) So, in fact, you could do this with a 15*5 pixel image (74 pixels, 3*15*5 = 225 bytes), which is smaller than a 9x9 image (81 pixels, 3*9*9 = 243 bytes). The disassembly of IQ's tunnel code is
    Code:
    00000100  B7 10              mov bh,0x10
    00000102  B4 4A              mov ah,0x4a
    00000104  CD 21              int 0x21
    00000106  B4 48              mov ah,0x48
    00000108  CD 21              int 0x21
    0000010A  8E E8              mov gs,ax
    0000010C  B7 20              mov bh,0x20
    0000010E  B4 48              mov ah,0x48
    00000110  CD 21              int 0x21
    00000112  8E E0              mov fs,ax
    00000114  8E C0              mov es,ax
    00000116  BD DD 01           mov bp,0x1dd
    00000119  B1 C8              mov cl,0xc8
    0000011B  31 FF              xor di,di
    0000011D  BB 60 FF           mov bx,0xff60
    00000120  89 C8              mov ax,cx
    00000122  2D 64 00           sub ax,0x64
    00000125  89 46 03           mov [bp+0x3],ax
    00000128  89 5E 05           mov [bp+0x5],bx
    0000012B  DF 46 05           fild word [bp+0x5]
    0000012E  DF 46 03           fild word [bp+0x3]
    00000131  D9 C0              fld st0
    00000133  DC C8              fmul to st0
    00000135  D9 C2              fld st2
    00000137  DC C8              fmul to st0
    00000139  DE C1              faddp st1
    0000013B  D9 FA              fsqrt
    0000013D  DE 7E 01           fidivr word [bp+0x1]
    00000140  26 DF 1D           fistp word [es:di]
    00000143  D9 F3              fpatan
    00000145  DE 4E 00           fimul word [bp+0x0]
    00000148  26 DF 5D 01        fistp word [es:di+0x1]
    0000014C  47                 inc di
    0000014D  47                 inc di
    0000014E  43                 inc bx
    0000014F  81 FB 9F 00        cmp bx,0x9f
    00000153  7E CB              jng 0x120
    00000155  8C C0              mov ax,es
    00000157  05 28 00           add ax,0x28
    0000015A  8E C0              mov es,ax
    0000015C  E2 BD              loop 0x11b
    0000015E  88 C8              mov al,cl
    00000160  30 E8              xor al,ch
    00000162  89 CB              mov bx,cx
    00000164  65 88 07           mov [gs:bx],al
    00000167  E2 F5              loop 0x15e
    00000169  B1 10              mov cl,0x10
    0000016B  65 8A 07           mov al,[gs:bx]
    0000016E  FE CB              dec bl
    00000170  65 02 07           add al,[gs:bx]
    00000173  FE C3              inc bl
    00000175  FE C7              inc bh
    00000177  65 02 07           add al,[gs:bx]
    0000017A  80 EF 02           sub bh,0x2
    0000017D  65 02 07           add al,[gs:bx]
    00000180  FE C7              inc bh
    00000182  C1 E8 02           shr ax,byte 0x2
    00000185  65 88 07           mov [gs:bx],al
    00000188  43                 inc bx
    00000189  75 E0              jnz 0x16b
    0000018B  E2 DE              loop 0x16b
    0000018D  B0 13              mov al,0x13
    0000018F  CD 10              int 0x10
    00000191  68 00 A0           push word 0xa000
    00000194  07                 pop es
    00000195  88 C8              mov al,cl
    00000197  BA C8 03           mov dx,0x3c8
    0000019A  EE                 out dx,al
    0000019B  42                 inc dx
    0000019C  EE                 out dx,al
    0000019D  EE                 out dx,al
    0000019E  EE                 out dx,al
    0000019F  E2 F4              loop 0x195
    000001A1  45                 inc bp
    000001A2  B2 DA              mov dl,0xda
    000001A4  EC                 in al,dx
    000001A5  A8 08              test al,0x8
    000001A7  74 FB              jz 0x1a4
    000001A9  EC                 in al,dx
    000001AA  A8 08              test al,0x8
    000001AC  75 FB              jnz 0x1a9
    000001AE  0F A0              push fs
    000001B0  31 FF              xor di,di
    000001B2  B1 C8              mov cl,0xc8
    000001B4  31 F6              xor si,si
    000001B6  64 8B 1C           mov bx,[fs:si]
    000001B9  01 EB              add bx,bp
    000001BB  65 8A 07           mov al,[gs:bx]
    000001BE  AA                 stosb
    000001BF  AD                 lodsw
    000001C0  81 FE 80 02        cmp si,0x280
    000001C4  7C F0              jl 0x1b6
    000001C6  8C E0              mov ax,fs
    000001C8  05 28 00           add ax,0x28
    000001CB  8E E0              mov fs,ax
    000001CD  E2 E5              loop 0x1b4
    000001CF  0F A1              pop fs
    000001D1  B4 11              mov ah,0x11
    000001D3  CD 16              int 0x16
    000001D5  74 CA              jz 0x1a1
    000001D7  B8 03 00           mov ax,0x3
    000001DA  CD 10              int 0x10
    000001DC  C3                 ret
    000001DD  29 00              sub [bx+si],ax
    000001DF  0A                 db 0x0a
    The leftmost column is the address, the middle column describes the byte values in hexadecimal, and the right side tells us the assembly instruction the bytes encode. All you need to do, is to pick each set of three bytes, and you get your pixel color. So, the first one is #B710B4 (red=0xB7=183, green=0x10=16, blue=0xB4=180), the second one #4ACD21 (red=74, green=205, blue=33), the third B448CD (red=180, green=72, blue=205), and so on.

    Overall, it is very simple. You encode assembly instructions using RGB colors; three bytes per pixel. The actual image produced by the above assembly code, appending 19 bytes of 255 (so that the unused pixels will be white), scaled 10x, is
    Real pixel coding-iqtunnel-90x90-png

    Now, you obviously don't think up the code while drawing! That'd be just silly. In fact, if you look closely at the video, you can tell how the author does it: they use the color picker to pick the color (from somewhere outside the video capture).

    The actual way this is done, is you first write or obtain the demo code, written in assembly. You run it, to make sure it works. Then, you decide the image size you want to use -- it has to be large enough, 3*width*height >= demo size in bytes. You pad the demo executable with 255 bytes, so that the unused pixels will be white.

    If you prepend "P6\nW\nH\n255\n" to the demo code (where W and H are the width and height of the image, as normal decimal numbers), you get a PPM format image file you can open in just about any image manipulation program. Assuming you have a two-monitor setup, with the left side being captured, you could just open this image in the right-side monitor, and zoom in so that you can easily and quickly pick pixel colors from it.

    Then, you just capture a video of you duplicating the colors from the unseen image to a newly created image, then save it in raw format, rename it to something.com so that it is executable in Windows, and execute it.

    Just a trick, and not even a good one.

    Questions?

  3. #3
    Tweaking master Aslaville's Avatar
    Join Date
    Sep 2012
    Location
    Rogueport
    Posts
    528
    Quote Originally Posted by Nominal Animal View Post

    Questions?
    TBQH I don't really understand how you get the colour code from the instruction bytes, assuming the address part is ignored.

  4. #4
    Registered User Alpo's Avatar
    Join Date
    Apr 2014
    Posts
    877
    Quote Originally Posted by Nominal Animal;

    Questions?
    So I would have to first make the assembly code, open it in a paint program (or whatever, append the data to a bitmap header or something), then pick the colors from it to make the .com file?

    Is there any real benefit to doing it like this? Was the last step of turning the information into a bitmap, and then making the .com out of it just for show?
    WndProc = (2[b] || !(2[b])) ? SufferNobly : TakeArms;

  5. #5
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Aslaville View Post
    TBQH I don't really understand how you get the colour code from the instruction bytes, assuming the address part is ignored.
    The raw format image file (as well as the PPM format image file) contains three bytes per pixel: red component, green component, and blue component. So, each three consecutive bytes specify one color.

    Let's take a look at the assembly code again:
    Code:
    00000100  B7 10              mov bh,0x10
    00000102  B4 4A              mov ah,0x4a
    00000104  CD 21              int 0x21
    00000106  B4 48              mov ah,0x48
    00000108  CD 21              int 0x21
    0000010A  8E E8              mov gs,ax
    The above code snippet defines the color for the first four pixels. It is a complete coincidence that these instructions all happen to be two bytes long; if you look at the full assembly listing, you see it's not the case generally. The first instruction encodes the red and green components of the first pixel, the second instruction encodes the blue component of the first pixel and the red component of the second pixel, and the third instruction encodes the green and blue components of the second pixel.

    The first 12 bytes of the file are
    Code:
     B7 10 B4  4A CD 21  B4 48 CD   21 8E E8
    and the first pixel color is therefore #B710B4, second #4ACD21, third #B448CD, fourth #218EE8, and so on.

    If you are wondering how to convert three byte values to an RGB triplet, see this Wikipedia article. It is really simple, though: you just convert the three bytes to decimal: B716 = 183, 1016 = 16, B416 = 180, so the RGB triplet for the first pixel is (red=183, green=10, blue=180).

    Quote Originally Posted by Alpo View Post
    So I would have to first make the assembly code, open it in a paint program (or whatever, append the data to a bitmap header or something), then pick the colors from it to make the .com file?
    No. When you compile the assembly shown in my previous post, you get the 224-byte executable .com file.

    (If you save the 224 bytes shown in the middle column, and name it something.com, you also get the exact same executable .com file.)

    The demo existed first. The video maker either opened it in raw format, or added the PPM header and padding bytes to open it, then copied it pixel-by-pixel by hand, without showing you the original (it's hidden to the right of the video). Saving the copied image as a raw image file recreates the original .com executable contents, and renaming it to .com makes it executable. So, all the pixel stuff is just recreating something that already exists.

    Quote Originally Posted by Alpo View Post
    Is there any real benefit to doing it like this?
    I've seen a man climb up a tree, butt first, up to a height of about three meters, and I can think of a couple of benefits of doing so.

    Doing the code via an image -- and lying about the actual image used, not mentioning the origin for the code, and so on -- is just sad. If they had referenced their sources, and been honest about it, I might call this showmanship, but as it is, it is just a sad attempt.

    Quote Originally Posted by Alpo View Post
    Was the last step of turning the information into a bitmap, and then making the .com out of it just for show?
    Yes, purely for show.

    It is like an old Unix programmer telling a youngster that "When I was young, we had to write code using these really thin, pointy magnets, directly on the hard disk platter. Remembering the bit pattern for each instruction, and dealing with binary values all around was the easy part; try keeping your hand steady and rythm correct after a couple hours of magnet-to-disk tapping!"

    You never write code using an image. (Old Commodore 64 games had cassette tape turbo loaders (using tighter magnetic coding) that used the display buffer for some of the loader code, but even that was because it was the easiest/least conflicting place in memory to put it, not because it was cool or otherwise useful.)

    I've written an old-format EXE relocation code incorporating a "secure" serial number verifier using DEBUG.EXE in early nineties (not having a valid MASM/TASM license) for a commercial program -- the video clip author uses it to show the assembly code corresponding to the image --, and that was tricky because it didn't support jump labels. Full assemblers let you edit the code, insert instructions, and calculates the address and jump offsets for you. Much easier.

    I do know some people who have had to construct assembly programs by looking up the opcodes and writing down the bytes, then programming the bytes directly on the device somehow, but that was back in the early days of computing (and they didn't mind doing it that way, as they were bootstrapping the architecture, doing that to write the tools that helped them not to have to do that ever again). Now, you can write a simple assembler in about the same time as it takes you to learn the intricacies of an architecture (it's actually one of the best ways to learn those!) using any of the scripting languages, probably even using Bash alone, and machines to run those are ubiquitous, so you never need to.

    Assembly itself is nowadays only needed for specific use cases: low-level code for exact hardware access patterns you cannot trust the C compilers to get right, and for microcontrollers and similar with very limited runtime and/or memory restrictions. (Stuff like Arduino libraries often contain assembly snippets.)

    So, the video is not even showy, just a dishonest trick.

    To recap:

    The 224-byte IQ tunnel demo was released in 2002. The video author took that, and modified it a bit, I think to make it run on newest Windows versions too (but they might have done more; the effect still looks exactly the same).

    The video author had the idea that they'll make a blog post and a video about how they "create" the demo program by drawing the exact pixels, so that when saved in raw image format, the file matches that of the demo .com executable.

    Except they didn't; they used the demo code to create an image (either loading it in raw image format, or prepending the PPM image header and padding bytes), and just copied the image, pixel by pixel. They kept the original off-video, to the right -- but you can still see how they used the color-picker tool and how the cursor sneaks to the right of the screen to pick the exact color "from somewhere".

  6. #6
    Citizen of Awesometown the_jackass's Avatar
    Join Date
    Oct 2014
    Location
    Awesometown
    Posts
    269
    Quote Originally Posted by Nominal Animal View Post
    I've seen a man climb up a tree, butt first, up to a height of about three meters, and I can think of a couple of benefits of doing so.
    Wow that's truly artistic. Not the epitome of art but still.
    "Highbrow philosophical truth: Everybody is an ape in monkeytown" --Oscar Wilde

  7. #7
    Tweaking master Aslaville's Avatar
    Join Date
    Sep 2012
    Location
    Rogueport
    Posts
    528
    Quote Originally Posted by Nominal Animal View Post
    The first 12 bytes of the file are

    Code:
     B7 10 B4  4A CD 21  B4 48 CD   21 8E E8
    and the first pixel color is therefore #B710B4, second #4ACD21, third #B448CD, fourth #218EE8, and so on.
    Thanks, that explains it. I was confused thinking that each instruction corresponds to a pixel - only the first pixel satisfied my criteria. Its very clear and silly now.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pixel by pixel graphics, what's the name of this technique?
    By PedroTuga in forum Game Programming
    Replies: 6
    Last Post: 12-14-2012, 07:06 PM
  2. Pixel's
    By cgod in forum C++ Programming
    Replies: 3
    Last Post: 03-20-2005, 04:19 AM
  3. Real Game Coding
    By Axpen in forum A Brief History of Cprogramming.com
    Replies: 26
    Last Post: 07-02-2003, 09:31 PM
  4. ...i have a pixel...
    By Sebastiani in forum Windows Programming
    Replies: 1
    Last Post: 09-06-2002, 04:17 PM
  5. Replies: 7
    Last Post: 12-12-2001, 10:28 AM