Mock API for RE in 5 minutes: An Example with Krisp
This article is machine translated which hasn’t been proofreaded by the author. The info it contains may be inaccurate. The author will do his best to get back (when he has time) and revise these articles. 🥰
For Chinese version of this article, see here.
When testing (po) and testing (jie) software, the last thing I want to encounter is that the target software has the function of network verification. Said to change the code, but I don’t know where there are hidden piles in the code, and it is very troublesome to change all the input and output points. Said to disconnect its Internet cafes, not all software provides offline activation. Today I introduce a four-two-catty network verification bypass method, no need to disconnect the network, less bytecode changes, and less than 100 lines of Python.~~ No loss, no evaporation, zero waste~~ 1.
Recently, I always have to use WeCom for online meetings at work meetings. I have to cast a screen on the computer, and I have to open the microphone (I can’t log in to multiple points, so I can’t use the microphone of my mobile phone). The sound quality of the computer microphone is really rubbish, and there is ambient noise. Search to find a software Krisp [^ krisp], which does audio processing at the sound card driver layer and reduces noise globally, which is very suitable for the application scenario I expected,~~ It’s a pity that it costs money~~. Constrained by the lack of cracking on the Internet, we can only use our ingenuity to “learn”.
In the first step of reversing, we must first know what programming language the software we want to reverse uses. The Krisp software is very simple, open the installation directory, and know from the < gt r = “3”/> file and the < gt r = “4”/> library it references, this software is written in C #.
C #is simple. Just drag it into dnSpy [^ dnspy] to open it. This tool is much more powerful than ILSpy back then. It can decompile, debug, and change program logic directly in C #. Moreover, many .NET framework programs are released without confusion. The variable and method names are clearly written. If you decompile it with dnSpy, it is basically not much different from looking at the program source code.
Search for common keywords in dnSpy. Through the keyword trial (trial), you can quickly locate the < gt r = “7”/> function. In this function, in addition to trial, there is also a mode called unlimited. Directly use dnSpy brainless to change it for him.
Well, at least the trial limit on the interface is gone, and it is already a distinguished VIP customer on the surface.
But this is not enough, because this is just a logical judgment related to the UI in the program, and there must be many similar modification points. Many logical judgments are realized by comparing with constants, which is not easy to find, and it is too troublesome to modify one by one.
So let’s change our thinking. The program authorization status is issued from the network, so we might as well take network communication as the starting point. Use the Fiddler packet capture mentioned in our previous article to see, it is still very simple, just flip through and you can find the < gt r = “10”/> API.
So what do we have to change it to when we’re done? First, the < gt r = “12”/> parameter in JSON has to be changed to unlimited. Second, there are a lot of parameter values of < gt r = “14”/> in the following < gt r = “13”/>, and these will definitely become False after the probation period (the account I registered has not passed the probation period yet, so just guessing). So when we intercept data and modify JSON, just fix these values to what they are now.
Comparison of cracking methods
Well, our favorite “why not use xxxxx” session is here again. There are not many contestants participating today,~~ Besides, I didn’t specifically search~~. Briefly compare.
< Gt r = “15”/> (final selection)
Advantages: There are fewer points that need to be modified in the program, just change the URL string. If you can construct a URL of the same length, you don’t even need a decompilation tool to change the source program, just replace the string directly. After the program is subsequently updated, the workload of maintaining the cracked version is very small.
< Gt r = “16”/> Method 2: Modify the client side and modify the return value at the REST API request point **
Disadvantages: To crack the new version, you have to go through all the steps all over again. And requests from different APIs may still be in different Classes. It takes a lot of effort to crack it just once.
< Gt r = “17”/> Method 3: Change hosts to intercept API requests **
It is not feasible, the API access of the production environment is https. This is not a traditional MITM attack, and sslstrip cannot be engaged. If the network is disconnected, there is no way to log in and use normally, and the normal functions are destroyed.
The framework used to build the API is~~ in the last article I said it was rubbish~~ mitmproxy. As the name suggests, this framework is used as a man-in-the-middle. The biggest difference between it and other programming language libraries is that it provides an API for < gt r = “18”/> web requests (close to the functionality of middleware in other frameworks), while other web frameworks provide < gt r = “19”/> Web request capability. For example, Django parses the web request out of the field and throws it to us, and the request cannot be sent. If I want to send this request again, I have to spell all the fields again and call requests to send it out. What if the target application has dozens of APIs? trouble no? We write code, only deal with the most important logic, don’t write boring CRUD, really do it, no churn, no evaporation, zero waste 1!
Other MITM tools are not applicable here. Can other tools be placed in a docker container and run on a VPS 24 hours a day?
Mock API build
The most important function of the counterfeit products API we built is that it allows us to modify the incoming request and return data in a similar way to writing middleware, and at the same time pass the unmodified API back intact. Of course, the less code you write, the better.
Now that the principles and tools are clear, let’s write the code according to the documentation. But when it comes to documentation, I have to remind that mitmproxy has no documentation at all (smile). According to the author’s experience, some example scripts in the project Github [^ s1] [^ s2] [^ s3] [^ s4], and the pydoc command line [^ doc] are two relatively good references. You can barely write according to the map.
When we run mitmproxy, we need to use its reverse proxy mode [^ dmode], in this mode mitmproxy will accept normal HTTP requests as input, not special HTTP Proxy requests. The complete operating parameters are as follows:
mitmproxy -p 8081 -s krisp.py --mode reverse:http://localhost --set keep_host_header
Among them, the host name after < gt r = “20”/> is entered casually, with the < gt r = “21”/> option, and manually set the Host field in the request Header to the destination host of the flow in the code, Only in this way can multiple destination hosts be reversed proxy on the same port ** at the same time **.
The following code implements [^ s1] [^ s4]:
- Redirect < gt r = “22”/> requests to < gt r = “23”/> to implement reverse proxy.
- Returns false return values for all requests for < gt r = “24”/>.
- Returns 404 for other hosts.
The < gt r = “26”/> function we defined in the previous code is the event API provided by mitmproxy. This function will be called before each request is made. Next we implement another < gt r = “27”/> function, this API will fire when mitmproxy gets the return data of the web request (similar to the idea in the previous article).
And what we have to do is very simple, we can implement all the changes to < gt r = “28”/> and < gt r = “29”/> that we said earlier.
Finally, according to the format in the code example, define the class and declare the list of plugins, you can run mitmdump to call this script. Here, we name it krisp.py and listen for API requests on port 8081. Mitmdump is different from mitmproxy. The latter is a TUI program with a user interface. The former is purely functional and has no interface. It can be compared to tcpdump of the http protocol. This is very suitable for long-term operation.
mitmdump -p 8081 -s krisp.py --mode reverse:http://localhost --set keep_host_header
Of course, it is impossible for us to run such a line of commands every time we open the software, how low. We can package it into a Docker container and get it on the server so that it can stay open.
If readers want to deploy an activation server that exposes the public network and runs continuously, it is recommended to hang an additional reverse generation in front, so that log rotate and rate limit are more convenient. The easiest way is to use docker compose to set a traefik in front, so that Even the SSL certificate doesn’t have to worry about it. However, this part of the configuration is beyond the scope of this article.
Last small modification
We built a fake API and had to make the target program use it. This is also very simple. Didn’t the packet capture just now catch two domain names, < gt r = “32”/> and < gt r = “33”/>. Directly change the content search to its own domain name and the port that mitmdump listens on, and that’s it.
This article is another lazy tutorial. Two tools, less than 100 lines of code, implement a magic revision REST API, and crack an application in a relatively simple way. Some people will say that your C #program is not confused and has no shell. Isn’t it amusing to reverse so simply? Think again, based on the idea of capturing packets, wow, even if the target application is a black box, guessing the meaning of API parameters is still simpler than guessing the value of registers. The most important thing is the idea of building a Web API and the usage of the mitmproxy framework, which may be a treasure trove of knowledge that can be used in other scenarios.