Rating: 4.3

# Secret Notes

Both the windows app and android app files are required for this one, but having them installed on windows/android is not required to solve the challenge. If you're not on windows (or don't want to install the app) you can get the files for the app by going to the install page, visiting the appinstaller link in the url for "Install for x86" (ms-appinstaller:?source=https://notes-distribution.azurewebsites.net/Notes.UWP_x86.appinstaller), and then grabbing the download link from there for the actual app (https://notes-distribution.azurewebsites.net/Notes.UWP_1.0.0.0_x86.appx).

## Windows App part

So the challenge has two apps because parts of the password are "encoded" differently in each app. The first section has us disassembling the windows app.

You can extract the appx file with 7-zip to see the files. The file to note is Notes.dll which is a .net dll and should be easy to decompile. (Normally I would recommend dnspy for decompilation since it's just ilspy but with more features, but it dies on the async methods, so use ilspy instead.)

When you open it, there's a PasswordChecker class that decompiles to this:

```cs
public class PasswordChecker : IPasswordChecker
{
public bool CheckPassword(string password)
{
if (password.Length == 29)
{
return DependencyService.Get<IPasswordChecker>().CheckPassword(password);
}
return false;
}
}
```

Looking for more references of `CheckPassword` doesn't give us much, so it must be stored somewhere outside of Notes.dll. I have no idea why it is, but instead you need to decompile entrypoint/Notes.UWP.exe (I think this is just where platform specific code goes) which has the actual PasswordChecker in it:

```cs
public class PasswordChecker : IPasswordChecker
{
public bool CheckPassword(string password)
{
byte[] bytes = Encoding.ASCII.GetBytes(password);
int[] array = Array.ConvertAll(bytes, (Converter<byte, int>)((byte item) => item));
bool flag = true;
flag &= (array[15] - array[24] - array[1] + array[6] == 90);
flag &= (array[17] - array[23] - array[2] == -123);
flag &= (array[28] == 125);
flag &= (array[17] * array[24] - array[3] - array[23] * array[2] == -4937);
flag &= (array[11] * array[14] - array[26] + array[7] + array[16] == 5105);
flag &= (array[3] - array[6] == -30);
flag &= (array[21] == 105);
flag &= (array[9] * array[27] - array[24] * array[21] - array[25] == 1129);
flag &= (array[18] * array[6] + array[23] * array[3] + array[20] == 17936);
flag &= (array[7] - array[13] + array[19] * array[5] == 13413);
return flag & (array[10] * array[0] * array[12] - array[26] == 837149);
}
}
```

Interesting. It looks like a fun z3 problem, but we run into issues if we try to use just this:

```python
>>> from z3 import *
>>> s = Solver()
# 32 bit numbers just so the below operations don't overflow
>>> ar = [BitVec(f'{i}', 32) for i in range(29)]
>>> s.add(ar[15] - ar[24] - ar[1] + ar[6] == 90)
>>> s.add(ar[17] - ar[23] - ar[2] == -123)
>>> s.add(ar[28] == 125)
>>> s.add(ar[17] * ar[24] - ar[3] - ar[23] * ar[2] == -4937)
>>> s.add(ar[11] * ar[14] - ar[26] + ar[7] + ar[16] == 5105)
>>> s.add(ar[3] - ar[6] == -30)
>>> s.add(ar[21] == 105)
>>> s.add(ar[9] * ar[27] - ar[24] * ar[21] - ar[25] == 1129)
>>> s.add(ar[18] * ar[6] + ar[23] * ar[3] + ar[20] == 17936)
>>> s.add(ar[7] - ar[13] + ar[19] * ar[5] == 13413)
>>> s.add(ar[10] * ar[0] * ar[12] - ar[26] == 837149)
# just make sure the character is (somewhat) valid
>>> s.add(ar[0] > 32)
>>> s.add(ar[0] < 127)
>>> s.add(ar[1] > 32)
>>> s.add(ar[1] < 127)
>>> s.add(ar[2] > 32)
>>> s.add(ar[2] < 127)
>>> s.add(ar[3] > 32)
>>> s.add(ar[3] < 127)
>>> s.add(ar[4] > 32)
>>> s.add(ar[4] < 127)
>>> s.add(ar[5] > 32)
>>> s.add(ar[5] < 127)
>>> s.add(ar[6] > 32)
>>> s.add(ar[6] < 127)
>>> s.add(ar[7] > 32)
>>> s.add(ar[7] < 127)
>>> s.add(ar[8] > 32)
>>> s.add(ar[8] < 127)
>>> s.add(ar[9] > 32)
>>> s.add(ar[9] < 127)
>>> s.add(ar[10] > 32)
>>> s.add(ar[10] < 127)
>>> s.add(ar[11] > 32)
>>> s.add(ar[11] < 127)
>>> s.add(ar[12] > 32)
>>> s.add(ar[12] < 127)
>>> s.add(ar[13] > 32)
>>> s.add(ar[13] < 127)
>>> s.add(ar[14] > 32)
>>> s.add(ar[14] < 127)
>>> s.add(ar[15] > 32)
>>> s.add(ar[15] < 127)
>>> s.add(ar[16] > 32)
>>> s.add(ar[16] < 127)
>>> s.add(ar[17] > 32)
>>> s.add(ar[17] < 127)
>>> s.add(ar[18] > 32)
>>> s.add(ar[18] < 127)
>>> s.add(ar[19] > 32)
>>> s.add(ar[19] < 127)
>>> s.add(ar[20] > 32)
>>> s.add(ar[20] < 127)
>>> s.add(ar[21] > 32)
>>> s.add(ar[21] < 127)
>>> s.add(ar[22] > 32)
>>> s.add(ar[22] < 127)
>>> s.add(ar[23] > 32)
>>> s.add(ar[23] < 127)
>>> s.add(ar[24] > 32)
>>> s.add(ar[24] < 127)
>>> s.add(ar[25] > 32)
>>> s.add(ar[25] < 127)
>>> s.add(ar[26] > 32)
>>> s.add(ar[26] < 127)
>>> s.add(ar[27] > 32)
>>> s.add(ar[27] < 127)
>>> s.add(ar[28] > 32)
>>> s.add(ar[28] < 127)
>>> s.check()
sat
>>> model = s.model()
>>> results = ([int(str(model[ar[i]])) for i in range(len(model))])
>>> print("".join([chr(item) for item in results]))
L-=JD{hADClWf;:E=/^m^iHm&(CM}
```

Which is not the password if you try it (if you have it installed), even though it does pass the check (you can just recompile that c# function and try yourself.)

So that means the other part is in the android app.

## Android App part

For the android app, again, you can just extract the apk with 7-zip or whatever. But there aren't any managed dlls just hanging around. They're actually stored in libmonodroid_bundle_app.so in the lib folder.

You can use https://github.com/tjg1/mono_unbundle to do that. Make sure you have `python-magic-bin` installed, otherwise it errors without telling you why.

Once you export the dlls, open Notes_Android.dll (not Notes.dll) to get the other part.

```cs
public bool CheckPassword(string password)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
CameraManager val = (CameraManager)Forms.get_Context().GetSystemService("camera");
string text = val.GetCameraIdList()[0];
CameraCharacteristics cameraCharacteristics = val.GetCameraCharacteristics(text);
StreamConfigurationMap val2 = (StreamConfigurationMap)cameraCharacteristics.Get(CameraCharacteristics.get_ScalerStreamConfigurationMap());
int num = 0;
Size[] outputSizes = val2.GetOutputSizes(256);
Size[] array = outputSizes;
foreach (Size val3 in array)
{
int num2 = val3.get_Height() * val3.get_Width();
if (num2 > num)
{
num = num2;
}
}
int num3 = (int)Math.Ceiling((double)num / 1024000.0);
DisplayInfo mainDisplayInfo = DeviceDisplay.get_MainDisplayInfo();
int num4 = (int)((DisplayInfo)(ref mainDisplayInfo)).get_Width();
int num5 = (int)((DisplayInfo)(ref mainDisplayInfo)).get_Height();
byte[] bytes = Encoding.ASCII.GetBytes(password);
int[] array2 = Array.ConvertAll(bytes, (Converter<byte, int>)((byte item) => item));
bool flag = true;
flag &= (array2[22] - array2[4] - array2[26] + array2[10] == 8 * num3);
flag &= (array2[20] + array2[27] + array2[6] == 249);
flag &= (array2[21] - array2[25] + array2[27] - array2[8] == 61);
flag &= (array2[24] + array2[9] * array2[21] + array2[23] == 12219);
flag &= (array2[0] + array2[28] * array2[12] + array2[19] - array2[11] == 39 + 13 * num4);
flag &= (array2[10] * array2[22] + array2[19] + array2[0] - array2[28] == 13274);
flag &= (array2[5] == 123);
flag &= (array2[17] - array2[25] - array2[2] + array2[18] == 35);
flag &= (array2[9] + array2[24] - array2[21] + array2[2] - array2[15] == 19);
flag &= (array2[13] * array2[22] + array2[16] * array2[11] == 1878 + 9 * num5);
return flag & (array2[4] == 71 + num3);
}
```

For whatever reason, some of the code is dependent on screen size, so we'll just ignore those bits of code when we put it into z3.

```python
>>> s = Solver()
>>> ar = [BitVec(f'{i}', 32) for i in range(29)]
>>> s.add(ar[15] - ar[24] - ar[1] + ar[6] == 90)
>>> s.add(ar[17] - ar[23] - ar[2] == -123)
>>> s.add(ar[28] == 125)
>>> s.add(ar[17] * ar[24] - ar[3] - ar[23] * ar[2] == -4937)
>>> s.add(ar[11] * ar[14] - ar[26] + ar[7] + ar[16] == 5105)
>>> s.add(ar[3] - ar[6] == -30)
>>> s.add(ar[21] == 105)
>>> s.add(ar[9] * ar[27] - ar[24] * ar[21] - ar[25] == 1129)
>>> s.add(ar[18] * ar[6] + ar[23] * ar[3] + ar[20] == 17936)
>>> s.add(ar[7] - ar[13] + ar[19] * ar[5] == 13413)
>>> s.add(ar[10] * ar[0] * ar[12] - ar[26] == 837149)
>>> #s.add(ar[22] - ar[4] - ar[26] + ar[10] == 8 * num3)
>>> s.add(ar[20] + ar[27] + ar[6] == 249)
>>> s.add(ar[21] - ar[25] + ar[27] - ar[8] == 61)
>>> s.add(ar[24] + ar[9] * ar[21] + ar[23] == 12219)
>>> #s.add(ar[0] + ar[28] * ar[12] + ar[19] - ar[11] == 39 + 13 * num4)
>>> s.add(ar[10] * ar[22] + ar[19] + ar[0] - ar[28] == 13274)
>>> s.add(ar[5] == 123)
>>> s.add(ar[17] - ar[25] - ar[2] + ar[18] == 35)
>>> s.add(ar[9] + ar[24] - ar[21] + ar[2] - ar[15] == 19)
>>> #s.add(ar[13] * ar[22] + ar[16] * ar[11] == 1878 + 9 * num5)
>>> s.add(ar[0] > 32)
>>> s.add(ar[0] < 127)
>>> s.add(ar[1] > 32)
>>> s.add(ar[1] < 127)
>>> s.add(ar[2] > 32)
>>> s.add(ar[2] < 127)
>>> s.add(ar[3] > 32)
>>> s.add(ar[3] < 127)
>>> s.add(ar[4] > 32)
>>> s.add(ar[4] < 127)
>>> s.add(ar[5] > 32)
>>> s.add(ar[5] < 127)
>>> s.add(ar[6] > 32)
>>> s.add(ar[6] < 127)
>>> s.add(ar[7] > 32)
>>> s.add(ar[7] < 127)
>>> s.add(ar[8] > 32)
>>> s.add(ar[8] < 127)
>>> s.add(ar[9] > 32)
>>> s.add(ar[9] < 127)
>>> s.add(ar[10] > 32)
>>> s.add(ar[10] < 127)
>>> s.add(ar[11] > 32)
>>> s.add(ar[11] < 127)
>>> s.add(ar[12] > 32)
>>> s.add(ar[12] < 127)
>>> s.add(ar[13] > 32)
>>> s.add(ar[13] < 127)
>>> s.add(ar[14] > 32)
>>> s.add(ar[14] < 127)
>>> s.add(ar[15] > 32)
>>> s.add(ar[15] < 127)
>>> s.add(ar[16] > 32)
>>> s.add(ar[16] < 127)
>>> s.add(ar[17] > 32)
>>> s.add(ar[17] < 127)
>>> s.add(ar[18] > 32)
>>> s.add(ar[18] < 127)
>>> s.add(ar[19] > 32)
>>> s.add(ar[19] < 127)
>>> s.add(ar[20] > 32)
>>> s.add(ar[20] < 127)
>>> s.add(ar[21] > 32)
>>> s.add(ar[21] < 127)
>>> s.add(ar[22] > 32)
>>> s.add(ar[22] < 127)
>>> s.add(ar[23] > 32)
>>> s.add(ar[23] < 127)
>>> s.add(ar[24] > 32)
>>> s.add(ar[24] < 127)
>>> s.add(ar[25] > 32)
>>> s.add(ar[25] < 127)
>>> s.add(ar[26] > 32)
>>> s.add(ar[26] < 127)
>>> s.add(ar[27] > 32)
>>> s.add(ar[27] < 127)
>>> s.add(ar[28] > 32)
>>> s.add(ar[28] < 127)
>>> s.check()
sat
>>> model = s.model()
>>> results = ([int(str(model[ar[i]])) for i in range(len(model))])
>>> print("".join([chr(item) for item in results]))
rLLED{cK0sl3DEct00rm_iz_13C7}
```

Hmm, this almost looks like a flag, but it seems kinda broken. If we know the first few characters, maybe we can get closer to the actual flag.

```python
...
>>> s.add(ar[27] > 32)
>>> s.add(ar[27] < 127)
>>> s.add(ar[28] > 32)
>>> s.add(ar[28] < 127)
>>> s.add(ar[0] == ord("A"))
>>> s.add(ar[1] == ord("L"))
>>> s.add(ar[2] == ord("L"))
>>> s.add(ar[3] == ord("E"))
>>> s.add(ar[4] == ord("S"))
>>> s.add(ar[5] == ord("{"))
>>> s.check()
sat
>>> model = s.model()
>>> results = ([int(str(model[ar[i]])) for i in range(len(model))])
>>> print("".join([chr(item) for item in results]))
ALLES{c~0ss'px~tt0rm_is_1337}
```

Ah, it looks like cross platform is 1337. Let's add a few more characters just to confirm how the flag is formatted.

```python
...
>>> s.add(ar[27] > 32)
>>> s.add(ar[27] < 127)
>>> s.add(ar[28] > 32)
>>> s.add(ar[28] < 127)
>>> s.add(ar[0] == ord("A"))
>>> s.add(ar[1] == ord("L"))
>>> s.add(ar[2] == ord("L"))
>>> s.add(ar[3] == ord("E"))
>>> s.add(ar[4] == ord("S"))
>>> s.add(ar[5] == ord("{"))
>>> s.add(ar[6] == ord("c"))
>>> s.add(ar[7] == ord("r"))
>>> s.add(ar[8] == ord("0"))
>>> s.add(ar[9] == ord("s"))
>>> s.add(ar[10] == ord("s"))
>>> s.add(ar[11] == ord("_"))
>>> s.add(ar[12] == ord("p"))
>>> s.add(ar[13] == ord("l"))
>>> s.check()
sat
>>> model = s.model()
>>> results = ([int(str(model[ar[i]])) for i in range(len(model))])
>>> print("".join([chr(item) for item in results]))
ALLES{cr0ss_pl4tf0rm_is_1337}
```

This is the windows app for secret notes:

![secretnotes](https://i.imgur.com/1K4zVkF.png)

Because the android one is dependent on screen size, and because mono_unbundle can't patch the dlls back in, I don't have a screenshot for the android one.