We are given a broken tar file and a dylib that was used to produce the archive. We can try to extract the tarball.

$ tar -xf flag.tar
tar: This does not look like a tar archive
tar: Skipping to next header
tar: Exiting with failure status due to previous errors
$ cat flag.txt
F5D1,4D6B,ED6A,08A6,38DD,F7FA,609E,EBC4,E55F,E6D1,7C89,ED5B,0871,1A69,5D58,72DE,224B,3AA6,0845,7DD6,58FB,E9CC,0A2D,76B8,ED60,251A,1F6B,32CC,E78D,12FA,201A,E889,2D25,922A,4BC5,F5FF,F8E5,C79B,3A77,4BDB,EA11,5941,58BD,3A95,F5C9,A225,AD40,F8BD,095D,70B6,458C,E7A9,EA68,252F,094B,5E41,0969,6015,5ED5,F6E5,59B9,7CAF,66DF,265B,7837,57B4,7CAF,AED9,F707,6A3C,F8E5,F509,7C8B,0915,2235,336F,33E9,2D14,7C91,5804,83E5,E78D,F4EA,0874,ED6B,4B35,E839,57B4,E77C,EA68,2525,AD41,ED6F,3A4A,4BCC,6015,F440,0858,3AA6,7809,671D,0874,EA77,63AF,2E91,5845,F6C4,086D,7795,3939,57B4,7C89,82DC,32ED,B994,C7AF,9135,0E65,1B66,ED5B,3235,6577,5A80,3AD3,E776,1EE5,AD41,ED59,864C,70B4,3876,ED67,64D6,F8E5,F505,EAD9,7C9C,32ED,B994,B4EF,0C6C,F665,F5F5,9047,521A,E99E,EA68,252F,9D09,76B7,E776,1ED0,095D,0D4D,5D5A,087B,2005,1526,7E76,85AD,78B9,E8B6,782C,251C,32ED,7F68,EBE3,EA41,57FD,ED59,846D,7A05,B994,BB78,ED6A,08A6,38DD,3B5D,7E45,E839,738C,E9CC,0A2D,764A,609E,E8B6,EA68,2524,E6BB,7C9C,639F,3A95,0895,F40F,8328,EA69,7EE5,F8BD,7F7D,0D6D,70B6,458C,E8B6,EA68,251C,6065,B35F,C789,5845,7F7D,6D89,4C6E,A20E,60B5,7E45,ED59,F707,69EF,922A,4BC5,F6EF,8635,F4B9,57B4,7CF8,ED60,2510,095D,20AF,3545,F40F,8328,EA41,58A4,225D,7E7C,4BDB,F8BD,082C,EAE7,5D57,5D50,0914,E7C7,8624,7CF8,ED60,2511,7C8E,7159,8416,7EF9,E7E5,774A,3895,1EC9,7C90,09B9,58BD,5FF5,E99E,EA68,250A,224C,EA3D,73F5,7C89,53A6,3190,3B5D,1526,7DD5,666A,0919,225F,CDEF,79E1,7E7B,7E6B,082C,A277,E885,E8BB,E775,5FF7,EA68,251B,7FDF,589D,7A05,779A,8A5A,7C91,5D5C,32ED,F628,2195,F49A,0C77,EAE1,59B9,58BD,E570,E99E,EA3D,73F9,13AD,2BF5,225D,7F7D,70B6,4A9C,337A,1EC9,4D05,7E75,2578,ED59,38E5,1ECA,A210,3B5D,779A,8A6F,C790,2518,4B41,7C89,5D49,4D05,152D,73C5,79F9,4BED,913C,37C9,5D4D,53C8,0941,7C97,5D5B,346A,82D8,5F36,801F,C800,

We see that output is some repeated format of “XXXX,”, where X stands for a hex character. Whatever is printing this seems to print the comma unconditionally, so we see if there are any decent strings with a comma in libarchive.dylib.

$ strings libarchive.dylib | grep ','
...
%04X,
...

Nice! So now we have a place to start reversing with. We open up libarchive.dylib in IDA, search strings for “%04X,”, discover it is only used in one place, and start disassembling there.

So we loop through some array called sub_101 and print out its values. Going through references to sub_101, we see that it is actually filled in via the update_sub_101 function (renamed after discovering it), so let’s reverse that and see what we find.

So what does really_update_sub_101 do? It takes an array of 3 integers and computes a base 40 sum.

And what about get_digit?

In the end, what this is essentially doing is taking some input string, looking up it’s position in ctable, and storing that into an array that encodes it as some base 40 numbers. If it’s in the second half (39 + i), we store [39, i] and if it’s in the first half (i), we just store [i]. We write every time we have 3 base 40 numbers and at the end, we append zeros until we have 3 base 40 digits. We now just undo the logic and print the result.

#! /usr/bin/env python2
v = [0xF5D1, 0x4D6B, 0xED6A, 0x08A6, 0x38DD, 0xF7FA, 0x609E, 0xEBC4, 0xE55F,
0xE6D1, 0x7C89, 0xED5B, 0x0871, 0x1A69, 0x5D58, 0x72DE, 0x224B, 0x3AA6,
0x0845, 0x7DD6, 0x58FB, 0xE9CC, 0x0A2D, 0x76B8, 0xED60, 0x251A, 0x1F6B,
0x32CC, 0xE78D, 0x12FA, 0x201A, 0xE889, 0x2D25, 0x922A, 0x4BC5, 0xF5FF,
0xF8E5, 0xC79B, 0x3A77, 0x4BDB, 0xEA11, 0x5941, 0x58BD, 0x3A95, 0xF5C9,
0xA225, 0xAD40, 0xF8BD, 0x095D, 0x70B6, 0x458C, 0xE7A9, 0xEA68, 0x252F,
0x094B, 0x5E41, 0x0969, 0x6015, 0x5ED5, 0xF6E5, 0x59B9, 0x7CAF, 0x66DF,
0x265B, 0x7837, 0x57B4, 0x7CAF, 0xAED9, 0xF707, 0x6A3C, 0xF8E5, 0xF509,
0x7C8B, 0x0915, 0x2235, 0x336F, 0x33E9, 0x2D14, 0x7C91, 0x5804, 0x83E5,
0xE78D, 0xF4EA, 0x0874, 0xED6B, 0x4B35, 0xE839, 0x57B4, 0xE77C, 0xEA68,
0x2525, 0xAD41, 0xED6F, 0x3A4A, 0x4BCC, 0x6015, 0xF440, 0x0858, 0x3AA6,
0x7809, 0x671D, 0x0874, 0xEA77, 0x63AF, 0x2E91, 0x5845, 0xF6C4, 0x086D,
0x7795, 0x3939, 0x57B4, 0x7C89, 0x82DC, 0x32ED, 0xB994, 0xC7AF, 0x9135,
0x0E65, 0x1B66, 0xED5B, 0x3235, 0x6577, 0x5A80, 0x3AD3, 0xE776, 0x1EE5,
0xAD41, 0xED59, 0x864C, 0x70B4, 0x3876, 0xED67, 0x64D6, 0xF8E5, 0xF505,
0xEAD9, 0x7C9C, 0x32ED, 0xB994, 0xB4EF, 0x0C6C, 0xF665, 0xF5F5, 0x9047,
0x521A, 0xE99E, 0xEA68, 0x252F, 0x9D09, 0x76B7, 0xE776, 0x1ED0, 0x095D,
0x0D4D, 0x5D5A, 0x087B, 0x2005, 0x1526, 0x7E76, 0x85AD, 0x78B9, 0xE8B6,
0x782C, 0x251C, 0x32ED, 0x7F68, 0xEBE3, 0xEA41, 0x57FD, 0xED59, 0x846D,
0x7A05, 0xB994, 0xBB78, 0xED6A, 0x08A6, 0x38DD, 0x3B5D, 0x7E45, 0xE839,
0x738C, 0xE9CC, 0x0A2D, 0x764A, 0x609E, 0xE8B6, 0xEA68, 0x2524, 0xE6BB,
0x7C9C, 0x639F, 0x3A95, 0x0895, 0xF40F, 0x8328, 0xEA69, 0x7EE5, 0xF8BD,
0x7F7D, 0x0D6D, 0x70B6, 0x458C, 0xE8B6, 0xEA68, 0x251C, 0x6065, 0xB35F,
0xC789, 0x5845, 0x7F7D, 0x6D89, 0x4C6E, 0xA20E, 0x60B5, 0x7E45, 0xED59,
0xF707, 0x69EF, 0x922A, 0x4BC5, 0xF6EF, 0x8635, 0xF4B9, 0x57B4, 0x7CF8,
0xED60, 0x2510, 0x095D, 0x20AF, 0x3545, 0xF40F, 0x8328, 0xEA41, 0x58A4,
0x225D, 0x7E7C, 0x4BDB, 0xF8BD, 0x082C, 0xEAE7, 0x5D57, 0x5D50, 0x0914,
0xE7C7, 0x8624, 0x7CF8, 0xED60, 0x2511, 0x7C8E, 0x7159, 0x8416, 0x7EF9,
0xE7E5, 0x774A, 0x3895, 0x1EC9, 0x7C90, 0x09B9, 0x58BD, 0x5FF5, 0xE99E,
0xEA68, 0x250A, 0x224C, 0xEA3D, 0x73F5, 0x7C89, 0x53A6, 0x3190, 0x3B5D,
0x1526, 0x7DD5, 0x666A, 0x0919, 0x225F, 0xCDEF, 0x79E1, 0x7E7B, 0x7E6B,
0x082C, 0xA277, 0xE885, 0xE8BB, 0xE775, 0x5FF7, 0xEA68, 0x251B, 0x7FDF,
0x589D, 0x7A05, 0x779A, 0x8A5A, 0x7C91, 0x5D5C, 0x32ED, 0xF628, 0x2195,
0xF49A, 0x0C77, 0xEAE1, 0x59B9, 0x58BD, 0xE570, 0xE99E, 0xEA3D, 0x73F9,
0x13AD, 0x2BF5, 0x225D, 0x7F7D, 0x70B6, 0x4A9C, 0x337A, 0x1EC9, 0x4D05,
0x7E75, 0x2578, 0xED59, 0x38E5, 0x1ECA, 0xA210, 0x3B5D, 0x779A, 0x8A6F,
0xC790, 0x2518, 0x4B41, 0x7C89, 0x5D49, 0x4D05, 0x152D, 0x73C5, 0x79F9,
0x4BED, 0x913C, 0x37C9, 0x5D4D, 0x53C8, 0x0941, 0x7C97, 0x5D5B, 0x346A,
0x82D8, 0x5F36, 0x801F, 0xC800]
ctable = "\x00abcdefghijklmnopqrstuvwxyz0123456789 \n\x00ABCDEFGHIJKLMNOPQRSTUVWXYZ([email protected]#,.?/*)<>"
# print "len(ctable): %d" % (len(ctable),)
v2 = []
for n in v:
c = n % 40
b = (n / 40) % 40
a = (n / 1600)
v2 += [a, b, c]
v3 = []
i = 0
while i < len(v2):
if v2[i] == 39:
v3 += [v2[i] + v2[i + 1]]
i += 2
else:
v3 += [v2[i]]
i += 1
# print v3
s = ""
for n in v3:
if ctable[n] != "\x00": s += ctable[n]
print s

Running gives

$ ./solve.py
Milos Raonic (born 1990) is a Canadian professional tennis player. He reached a career high world No. 4 singles ranking in May 2015, as ranked by the Association of Tennis Professionals (ATP). His career highlights include a Grand Slam final at the 2016 Wimbledon Championships and two Grand Slam semifinals at the 2014 Wimbledon Championships and 2016 Australian Open. He was the 2011 ATP Newcomer of the Year, and has been ranked continuously inside the top 20 since August 2012. Raonic is the first player born in the 1990s to win an ATP title, to be ranked in the top 10, and to qualify for the ATP World Tour Finals. He has eight ATP singles titles, all won on hard courts. He is frequently described as having one of the best serves among his contemporaries. Statistically, he is among the strongest servers in the Open Era, winning 91p of service games to rank third all time. Aided by his serve, he plays an all court style with an emphasis on short points.
$ ./solve.py | md5sum | awk '{print $1}'
2c8cd31daeba8753815851f13e6370b3