Calculating an Integer Overflow

I was playing an exploit game yesterday, and had to compute an exact value for an integer overflow, which made me think (when I’ve run into this before, I’ve just had to get ‘close enough’). In the binary, it compares some user input to the integer 9, which it must be “less than”

call _atoi
mov [ebp+var_C], eax
cmp [ebp+var_C], 9
jle short loc_8 ; process input and reach overflow

n is then multiplied by 4 to make room for 9 ints

shl eax, 2

var_c is then used as the n parameter in memcpy

void *memcpy(void *dest, const void *src, size_t n);

The vulnerability is possible (at least in part) to the shl, which can be used to wrap the integer and bypass the jle check. It’s fairly obvious there is an integer overflow here, and in fact, calculating n to be an exact value is also not difficult. So in my case I wanted n in the memcpy call to equal exactly 80.

The very first thing I did was to look at this http://en.wikipedia.org/wiki/Two’s_complement, which I remember having to do in school. It’s not complicated, but once you start throwing algebra in… anyway, so instead of using math I just wrote a wrapper program on the same machine.

#include <limits.h>
#include <stdio.h>

void main()
{
  //this should be 80. Sanity check
  int y =  -INT_MAX - INT_MAX + 78;
  printf("%dn", y); 

  printf("%dn", INT_MAX);
}

which prints

2147483647
80

Then just plop this in a calculator. Remember to divide by 4 to undo the multiply

>>> (-2147483647*2 + 78)/4.0
-1073741804.0

I entered this in the appropriate place, and set a breakpoint on the call to memcpy.

(gdb) x/d $esp+8
0xbffff2b8: 80

Success, we’ve managed to set n to 80. This one took more time to write out than to solve, but hey, maybe it will be useful for someone. Plus I needed a filler today… I have some cool stuff I’m working on, but it won’t be ready until at least next post, or maybe the post after :)

pydbg reverseme solution

Last week I wrote a keygen here.

This is an almost identical problem, but the binary has been patched to allow debugging (I may do this programmaticly as well, but not yet). I wanted to solve this with programmatic debugging. Here is the exe:
Ice9pch3.

The code simply sets a breakpoint and prints the key to the screen. Also it patches the process memory so that the serial is valid.

import sys
import ctypes

from pydbg import *
from pydbg.defines import *


print "This is a very stupid keygen that uses a debug method and grabs the key from memory"
print "prints out the valid key, and writes it to memory"
print "Basically, pydbg 'hello, world'"
print "-------------"

if len(sys.argv) != 2:
    print "Error. USAGE: keygen.py C:fullpathice"
    sys.exit(-1)

def handler_breakpoint(mdbg):
    valid_str = ""
    #the valid serial is at 004030C8
    addr = 0x004030C8
    while 1:
        tmp = mdbg.read(addr, 1)
        addr += 1
        if tmp != "x00":
            valid_str = valid_str + tmp
        else:
            break
    print "The valid string is: ", valid_str
    print "Writing this to memory..."
    #write this to memory at 004030b4
    #def write (self, address, data, length=0)
    wdata = ctypes.create_string_buffer(valid_str)
    mdbg.write(0x00403198, wdata, len(valid_str))
    #checking the write
    #print mdbg.read(0x00403198, len(valid_str) + 1)
    return DBG_CONTINUE

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, handler_breakpoint)
dbg.load(sys.argv[1])
dbg.debug_event_iteration()
#at 004011FF in execution, 
#def bp_set (self, address, description="", restore=True, handler=None):
dbg.bp_set(0x004011F5)
dbg.debug_event_loop()

Updated solution. I change a register now to circumvent the isdebuggerpresent call.

import sys
import ctypes

from pydbg import *
from pydbg.defines import *


print "This is a very stupid keygen that uses a debug method and grabs the key from memory"
print "prints out the valid key, and writes it to memory"
print "Basically, pydbg 'hello, world'"
print "-------------"

if len(sys.argv) != 2:
    print "Error. USAGE: keygen.py C:fullpathice"
    sys.exit(-1)

def handler_breakpoint(mdbg):
    if mdbg.get_register("EIP") == 0x004011F5:
        valid_str = ""
        #the valid serial is at 004030C8
        addr = 0x004030C8
        while 1:
            tmp = mdbg.read(addr, 1)
            addr += 1
            if tmp != "x00":
                valid_str = valid_str + tmp
            else:
                break
        print "The valid string is: ", valid_str
        print "Writing this to memory..."
        #write this to memory at 004030b4
        #def write (self, address, data, length=0)
        #wdata = ctypes.create_string_buffer(valid_str)
        mdbg.write(0x00403198, valid_str, len(valid_str))
        #checking the write
        #print mdbg.read(0x00403198, len(valid_str) + 1)
    if mdbg.get_register("EIP") == 0x40106e:
        mdbg.set_register("EAX", 0)
    return DBG_CONTINUE

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, handler_breakpoint)
dbg.load(sys.argv[1])
dbg.debug_event_iteration()
#0x40106e is the point where we can circumvent the isdebugger present call
dbg.bp_set(0x40106e)
#at 004011FF in execution, 
#breakpoing for reading writing final compare
dbg.bp_set(0x004011F5)
dbg.debug_event_loop()

Reverseme Windows Keygen

This one was challenging for me, and took me several hours, but was fun. I got caught up on certain parts that may not have been too difficult, but, yeah…

http://crackmes.de/users/tripletordo/ice9/

You can download the executable here Ice9.zip.

The first thing I noticed is probably the ‘trick’ which was simply a call to isdebuggerpresent. I modified the assembly immediately after from JNE to JE so that it only runs if a debugger is present, allowing me to attach my debugger.

00401071 74 0A JE SHORT Ice9.0040107D

This took a lot of trial and error. My strategy was to replicate the logic. Once I got to the point ‘ecx at 0040119c’ I was home free.

#include <iostream>
#include <string>
using namespace std;

void main (int argc, char *argv[]) {
  if ( argc != 2) {
    cout<<"Bad usage, enter a name > 4 letters"<<endl;
	return;
  }
  string name = argv[1];
  string ostring = name;
  int i;
  //first reverse the string
  for (i=0; i<name.length(); i++) {
    name[i] = ostring [name.length()-i-1];
  }
  
  if (name.length() < 4) {
    cout << "name must be more than 4 letters chief"<<endl;
	return;
  }
  

  int v1 = 0;
  int cum = 0;
  for (i=1; i<name.length(); i++) {
    v1 = name[i];
	if (name[i] <= 90) {
	  if (v1 >= 65)
	    v1 += 44;
	}
	cum += v1;
  } //ecx at 0040119C
  
  cum = 9 * (12345 * (cum + 666) - 23);
  
  char chr_403119 [122];
  unsigned int v;
  i=0;
  //no bounds checking
  do {
    v = cum;
	cum /= 0xA;
	chr_403119[i++] = v % 10 + 48;
  } while (v / 10);
  chr_403119[i] = '\0';
  
  printf ("%s", chr_403119);
  string serial = "";

  //reverse the string
  for (; i >= 0; --i) {
    serial += chr_403119[i];
  }
  cout<<serial<<endl;
  
  //append all chars except the 'first' three to the end 
  for (i=3; i< ostring.length(); i++) {
    serial += ostring[i];
  }
  
  cout<<serial<<endl;

}

My plan on this one, since it was interesting enough and because it’s relatively easy to break at the final value, is to break this a completely different way. I’d like to write a python debugging script that bypasses the isdebuggerpresent and just grabs the final value in the compare at 004011FF. This should be relatively straightforward, and hopefully a good ‘hello, world’ to the world of python debugging. Stay tuned.

Reverseme: Namegenme

This guy is here: http://crackmes.de/users/moofy/moofys_namegenme/

namegenme.zip

I had a fairly hard time with this one for some reason, although the solution was right in front of my face…

Most the logic for calculating the generation is in the function 00401852. The Serial is stored in a global variable, and the name is generated by taking certain bytes from the serial and doing addition on them.

Here is all the relevant logic, although finding it was sort of a pain.


.text:004018FD                 lea     eax, [ebp+var_10]
.text:00401900                 add     dword ptr [eax], 4
.text:00401903                 lea     eax, [ebp+var_14]
.text:00401906                 sub     dword ptr [eax], 3
.text:00401909                 lea     eax, [ebp+var_18]
.text:0040190C                 sub     dword ptr [eax], 2
.text:0040190F                 lea     eax, [ebp+var_1C]
.text:00401912                 add     dword ptr [eax], 2
.text:00401915                 lea     eax, [ebp+var_20]
.text:00401918                 dec     dword ptr [eax]
.text:0040191A                 lea     eax, [ebp+var_24]
.text:0040191D                 add     dword ptr [eax], 3
.text:00401920                 lea     eax, [ebp+var_28]
.text:00401923                 sub     dword ptr [eax], 2
.text:00401926                 lea     eax, [ebp+var_2C]
.text:00401929                 sub     dword ptr [eax], 4
.text:0040192C                 lea     eax, [ebp+var_30]
.text:0040192F                 add     dword ptr [eax], 3
.text:00401932                 lea     eax, [ebp+var_34]
.text:00401935                 inc     dword ptr [eax]

Here is a keygen written in C

void main(int argc, char* argv[]) {

  char Name [10];
  char* ser = argv[1];
  if (argc != 2 || strlen(argv[1]) < 21) {
    printf("Invalid serialn");
	return (-1);
  }

  Name[0] = ser[0] + 4;
  Name[1] = ser[1] - 3;
  Name[2] = ser[2] - 2;
  Name[3] = ser[6] + 2;
  Name[4] = ser[7] - 1;
  Name[5] = ser[8] + 3;
  Name[6] = ser[13] - 2;
  Name[7] = ser[14] - 4;
  Name[8] = ser[15] + 3;
  Name[9] = ser[20] + 1;
  Name[10] = "\0";

  printf("Name: %sn", Name);
}

Reverseme: Easy Windows Using Reflector

http://crackmes.de/users/d0min4ted/keygenme_by_d0min4ted/

In case the link goes away, here is a zip of the executable. crackme

I cheated on this one and used reflector. This was an excuse for me to try reflector out… so I started with that in mind.

The Checking code ends up being in crackme->WindowsFormsApplication4->Form1. You can deduce what most the buttons do. The relevant one turns out to be in asd. The keygen is basically straight from the verifying function found there, written in C#.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace keygen
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Name: ");
            string Name = Console.ReadLine();
            if (Name.Length < 4)
            {
                Console.WriteLine("Name must be 4 characters");
                Environment.Exit(0);
            }

            string str3 = "";
            char[] chArray = Name.ToCharArray();
            foreach (char ch in chArray)
            {
                int num2 = Convert.ToInt32(ch);
                string str4 = string.Format("{0:X}", num2);
                str3 = str3 + str4;
            }
            char[] array = str3.ToCharArray();
            Array.Reverse(array);
            string str5 = new string(array);
            if (str5.Length > 9)
            {
                str5 = str5.Remove(9, str5.Length - 9);
            }
            decimal num4 = Convert.ToDecimal(Convert.ToInt32(str5));
            double num5 = Math.Pow((double)Name.Length, 3.0);
            decimal num6 = Math.Round((decimal)(num4 * Convert.ToDecimal(num5)), 0);
            Console.WriteLine(num6);
        }
    }
}