You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _posts/2022-05-09-sdctf-magic3.md
+13-18
Original file line number
Diff line number
Diff line change
@@ -44,14 +44,14 @@ Don't forget to tick the `Signed jump table elements` - the data at `unk_6084` (
44
44
Nice! It's now showing what all the branches are doing in the decompilation. Ignoring the C++ boilerplates, it looks like aside from case 3 which jumps to `fail()` instantly, all 6 of the rest of the cases set some integer values before calling `magic1`, repeating this process 5 times in total. After poking around for a while, we can already reason about what the program is doing on the high level:
45
45
- Before main, a static initializer `_GLOBAL__sub_I__Z11magic_wordsB5cxx11` is run by `_libc_csu_init`, which sets `magic_word` to the string `ldr buf`.
46
46
- Once in main, it first calls setup_magic(), which sets up `magic_array` with consecutive integers with `std::iota`, then issues multiple calls to `magic1` with quite a bit of integers passed to it.
47
-
- It then accepts 1 line of input with no length limit that matches any character in `magic_word`, maps the characters to the cases (aside from ``), and process it by calling `magic1` 5 times with the integer parameters set before each call.
47
+
- It then accepts 1 line of input with no length limit that matches any character in `magic_word`, maps the characters to the cases (aside from the space), and process it by calling `magic1` 5 times with the integer parameters set before each call.
48
48
- Finally, it calls `test_magic` which iterates over the `magic_array`, printing the flag after asserting that `magic_array` consists of only ascending consecutive integers, just like the original state right after `std::iota`.
49
49
50
50
The only piece of the *puzzle* left now is to figure out what `magic1` is doing. Turns out, it is also quite straightforward:
It loops over the values passed to the function, utilizing the values as indexes to pairwise swap the elements in `magic_array`. Note that it loops the indexes from the bottom up when considering the order shown in the decompilation - this is due to how varargs are handled in C++, where it takes the values furthest from the stack pointer first. Considering how simple this entire program is, why is it called magic, and to the extent of a *cube* even?
54
+
It loops over the values passed to the function, utilizing the values as indexes to pairwise swap the elements in `magic_array`. Note that it loops the indexes from the bottom up when considering the order shown in the decompilation - this is due to the call to `std::reverse`. Considering how simple this entire program is, why is it called magic, and to the extent of a *cube* even?
55
55
<br><br>
56
56
57
57
## Magic-ematics
@@ -74,12 +74,13 @@ magic = [
74
74
defpairwise(iterable):
75
75
a, b = itertools.tee(iterable)
76
76
next(b, None)
77
-
returnzip(a, b)
77
+
returnzip(a, b)
78
78
79
79
defswapall(arr, indexes):
80
80
for i, j in pairwise(indexes[::-1]): #reverse the indexes as noted in the above section
81
81
arr[i-1], arr[j-1] = arr[j-1], arr[i-1]
82
82
83
+
# accepts argument as input
83
84
test = sys.argv[1] iflen(sys.argv) >1else''
84
85
85
86
defl(na):
@@ -131,7 +132,7 @@ for c in test:
131
132
132
133
print(", ".join([str(i+1) +":"+str(v) for i,v inenumerate(magic)]))
133
134
```
134
-
With some help of a native debugger and some breakpoints before `test_magic`, we can verify that their output do indeed match. After staring at it for quite a while, it still didn't seem like there is any pattern that we can identify - the values all seem quite arbitrary. Guess we might as well write a brute force script to run in the background while we figure the logic out:
135
+
With some help of a native debugger and some breakpoints before `test_magic`, we can verify that their outputs do indeed match. However, after staring at it for quite a while, it still didn't seem like there is any pattern that we can identify - the values all seem quite arbitrary. Guess we might as well write a brute force script to run in the background while we figure the logic out:
135
136
```java
136
137
importjava.time.OffsetDateTime;
137
138
importjava.time.format.DateTimeFormatter;
@@ -146,22 +147,16 @@ public class DeMagic {
146
147
privatestaticForkJoinPool ex =newForkJoinPool(28);
0 commit comments