Page 1 of 1
Black Box
Posted: Thu Feb 12, 2009 12:07 am
by megabreit
Looking to the disassembly it was time to polish my old C knowledge a bit.
Code: Select all
# include <stdio.h>
# include <values.h>
int main (int argc, char** argv)
{
signed int i;
for (i=MININT; i<MAXINT; i++)
{
register arg=i;
register arg1=arg;
arg=arg>>0x1f;
arg=~arg;
arg=arg&arg1;
arg-=0x6fe5d5;
arg=arg^0x2eb22189;
arg=arg*0x1534162;
arg=arg^0x69f6bc7;
if (arg==230392619) {printf("%i\n",i);}
}
}
This one is exactly the same as the source because it generates to same assembler code (the type "register" is important!)
I thought of coding it in some scripting language, but was not sure how to code the arithmetic with 32 bit signed integers.
The result: a rocket fast program (takes a few seconds to complete) and some C back into my brain
Anybody did it in a scripting language? How?
Posted: Thu Feb 12, 2009 12:51 am
by gfoot
I used Python, explicitly rounding modulo 2**32 in places. Rather than brute-forcing, having rewritten the steps, I worked back from the answer deciding which inputs at each step gave the right intermediate result. It wasn't too hard, though there were often several possible intermediates; however it always turned out that one was impossible due to an earlier step.
Probably much quicker to brute force it, though, as you say.
Posted: Sun Mar 08, 2009 1:15 pm
by homeas
@gfoot yes indeed, running the assembler part in Delphi on an old P4 you only need 11 secs -- so it is not really efficient to recalculate backwards (although that looks quite easy too, but surely will take more than 11 s). This challenge was a kind of recreation - after a lot of really hard challenges ...
Posted: Thu Apr 23, 2009 2:11 pm
by man
Code: Select all
#include <iostream>
int main()
{
int out = 230392619;
// 1. bruteforce
/*for( int i = 0; ; ++i )
{
int edx = i;
edx -= 0x6FE5D5;
edx ^= 0x2EB22189;
edx *= 0x1534162;
edx ^= 0x69F6BC7;
if( edx == out )
{
std::cout << i << std::endl;
break;
}
}*/
// 2. inversion
int x, edx = out;
edx ^= 0x69F6BC7;
// inversion of the multiplication: can this be done more efficiently?
for( x = 0 ; x * 0x1534162 != edx ; ++x ); edx = x;
edx ^= 0x2EB22189;
edx += 0x6FE5D5;
std::cout << edx << std::endl;
return 0;
}
Is there a better way to invert the multiplication?
Posted: Wed May 12, 2010 2:15 pm
by OKOB
My solution
Code: Select all
#include "stdafx.h"
#include "stdio.h"
int main(int argc, char* argv[])
{
unsigned int j;
for(unsigned int i=0; i<0xFFFFFFFF; i++) {
_asm {
push eax
push edx
mov eax, i
mov edx, eax
sar edx, 1Fh
not edx
and edx, eax
sub edx, 0x6FE5D5
xor edx, 0x2EB22189
imul edx, 0x1534162
xor edx, 0x69F6BC7
mov j, edx
pop edx
pop eax
}
if(j == 230392619)
break;
}
printf("%d\n", i);
return 0;
}
Java
Posted: Tue Jul 06, 2010 2:34 pm
by b0bA
Code: Select all
public class Blackbox {
public static void main(String[] args) {
int x = 0;
int s = 230392619;
int i = 0;
int ul = Integer.MAX_VALUE;
while (x!=s) {
x = ((( ul & i - 7333333 ) ^ 783425929 ) * 22233442 ) ^ 111111111;
i++;
}
System.out.println("Solution:"+(i-1));
}
}
Posted: Sat Jan 28, 2012 2:00 pm
by kne1p
man wrote:Is there a better way to invert the multiplication?
Code: Select all
int i, d = 0;
i = 230392619;
i ^= 0x69f6bc7;
d = i / 0x1534162;
while (d++ * 0x1534162 != i);
i = d ^ 0x2eb22189;
i += 0x6fe5d5;
I guess not, therefore the reverse calculation is only about twice as fast as the normal brute force approach.
Posted: Sun Feb 12, 2012 2:08 pm
by laz0r
I found the first few thousand values and worked out that the bit in position n is periodic in 2^n, so after working out what the last 16 bits had to be, I ended up with having to be congruent to 20148 mod 32768. That was enough to brute force in 15 mins.
Posted: Mon Feb 27, 2012 9:16 am
by aurora
i used brute force
... i had a machine lying around with a fast CPU and enough RAM to fit the entire system in. i used a tinycore linux and a ramdisk, to reduce IO. the shell script i used:
Code: Select all
#!/usr/bin/env bash
max=2147483647
threads=100
steps=$((max / threads + 1))
function test {
local s=$1
local e=$2
local t=$3
while [[ $s -lt $e ]]; do
v=`./onetest $s`
echo "$s = $v" | tee status.$t.log | grep 230392619
s=$((s + 1))
done
}
for (( i=0; i<$threads; i++ )); do
s=$((i * steps))
e=$(((i + 1) * steps))
((test $s $e $i &) &)
done
still took long enough ...
Posted: Tue Apr 17, 2012 7:50 pm
by ftfish
kne1p wrote:
I guess not, therefore the reverse calculation is only about twice as fast as the normal brute force approach.
Well, what you have to solve is the linear congruence equation: x*22233442 == 186968300 (mod 4294967296).
This can be done with knowledge of elementary number theory (extended euclidean algorithm). The time complexity is just O(logN) instead of O(N) where N is the largest number above.
Posted: Wed Jun 27, 2012 1:39 pm
by AMindForeverVoyaging
megabreit wrote:(the type "register" is important!)
Actually, it works just fine without.
This was a great challenge!
At first, I tried to get the GLIBC version 2.0, since seemingly that was used for creating the binary. I found that version on the GNU ftp server. However it would not compile - there was always some error with some time header file(s) that I was not able to fix.
So I got myself a disassembler (I used IDA Pro Free), looked at the instructions, and decided to reverse engineer the code. This worked out quite nicely. My solution:
Code: Select all
#include <stdio.h>
#include <stdlib.h>
#define SAR_CONSTANT 0x1F
#define SUB_CONSTANT 0x6FE5D5
#define XOR_CONSTANT_1 0x2EB22189
#define MUL_CONSTANT 0x1534162
#define XOR_CONSTANT_2 0x69F6BC7
inline int onetest(int input)
{
int temp;
temp = input;
input = (input >> SAR_CONSTANT); // SAR
input = (~input); // NOT
input = (input & temp); // AND
input = (input - SUB_CONSTANT); // SUB
input = (input ^ XOR_CONSTANT_1); // 1st XOR
input = (input * MUL_CONSTANT); // IMUL
input = (input ^ XOR_CONSTANT_2); // 2nd XOR
return input;
}
int main(int argc, char** argv)
{
unsigned int i;
for (i=0; i<0xFFFFFFFF; i++)
{
if ( onetest(i) == 230392619 )
printf("Solution: %d\n", i);
}
return 0;
}
Posted: Fri Jun 29, 2012 8:47 am
by captainfox
Nice challenge!
Tried it with IDA too, my decompiler returned a somewhat packed version of the calculation.
Brute force script ran about 6 seconds on my machine before spitting out the answer:
Code: Select all
#include <stdio.h>
int main(int argc, char **argv, char **envp) {
for (int i = 0; i <= 2147483647; i++) {
if ((22233442 * (((i & ~(i >> 31)) - 7333333) ^ 0x2EB22189) ^ 0x69F6BC7) == 230392619) {
printf("%d\n", i);
break;
}
}
}
Posted: Sat Jul 20, 2013 6:16 pm
by godefv
ftfish wrote:kne1p wrote:
I guess not, therefore the reverse calculation is only about twice as fast as the normal brute force approach.
Well, what you have to solve is the linear congruence equation: x*22233442 == 186968300 (mod 4294967296).
This can be done with knowledge of elementary number theory (extended euclidean algorithm). The time complexity is just O(logN) instead of O(N) where N is the largest number above.
+1
the extended euclidean algorithm got the division for me as well. it is actually the same problem as in the previous challenge Patience with the only difference being decompiling java class or elf binary.
This doesn't involve coding at all ! We could just calculate the answer by hand quite easily :p
I used gdb to disassemble the elf and used the value from the assembler code.
Posted: Tue Dec 01, 2015 4:50 pm
by Hippo
After finding boomerang could decompile it ... I wrote bruteforce to inverse the multiplication. It was that fast that I have not figured the euclidian algorithm will help.