Tensorflow+Android應用安全初探
1. 背景
2017年,谷歌發布了一個專門針對移動設備優化的Tensorflow版本——Tensorflow Lite,並於年末開放了開發者預覽版。
當前ML,DL系統通常軟體服務商的服務端為用戶進行服務,而此次Google希望能將一部分相關處理轉移到用戶的移動設備上,從而減輕服務端的壓力。同時,並且一些需要學習的用戶數據涉及用戶的敏感信息,並不適合通過網路連接發送給服務商,因此利用Tensorflow Lite可以使得在設備本地進行模型的train與inference。
2. 探究目的
從安全形度來看,相比於傳統的服務端集中學習,在移動設備上使用Tensorflow或是Tensorflow Lite會將訓練模型等信息集成進APK,然後對外發布。那麼所使用的訓練模型和參數等信息自然就可能被外部獲取。
本文將按照官方的例子對在APP內集成Tensorflow Lite進行分步學習,並且觀察最後的樣例APP中訓練模型相關的信息應該如何獲取與還原。
3.應用開發過程
對於Tensorflow Lite的詳細開發入門,可以參考項目官方頁面。安裝Tensorflow的過程就不多說了,本文將應用開發過程大致分為兩個階段:
1 生成TFLITE文件
2 開發APP
3.1 生成TFLITE文件
TFLITE文件就是Tensorflow Lite保存訓練模型與參數的文件,它是由Tensorflow的訓練模型文件.pb和參數文件.ckpt合成固定後生成的.pb文件進一步優化而成的,會更小且更適合在移動設備上運行。
大致流程圖如下:
那我們就使用項目中的cifar10樣例來運行一下…咦?報錯了?!這可是官方的例子啊?眾所周知,Tensorflow現在超級火,更新也超快,所以樣例代碼中的API有許多已經被修改。根據報錯去一個個搜即可,這裡前前後後加起來可能有十幾個報錯處需要修改。
成功運行後,我們發現會在/tmp/下產生訓練相關的文件,使用項目中freeze_graph.py這個工具來對目標訓練文件進行圖參數的固化從而產生.pb文件。同樣由於版本問題,我在運行項目中的這個固化腳本時存在一些報錯,本人使用了另一個修改腳本。
有了.pb文件後,我們可以使用toco工具將其轉化為我們所需要的.tflite文件。該工具全稱為,其可以將.pb文件(包含圖與參數信息)優化並轉化為.tflite文件,從而使其可以高效地在移動設備上運行。
官方對toco的使用方式如下:
bazel run--config=opt tensorflow/contrib/lite/toco:toco --
--input_file=(pwd)/mobilenet_v1_1.0_224/frozen_graph.pb
--input_format=TENSORFLOW_GRAPHDEF --output_format=TFLITE
--output_file=/tmp/mobilenet_v1_1.0_224.lite --inference_type=FLOAT
--input_type=FLOAT --input_arrays=input
--output_arrays=MobilenetV1/Predictions/Reshape_1 --input_shapes=1,224,224,3
為了方便使用該toco工具,可以直接用bazel先編譯成elf文件(64位直接點我),然後方便複製到/usr/bin下使其成為系統工具來使用。使用該工具時需要在眾多參數中仔細輸入正確的輸入輸出信息,然後就能成功製作出優化後的.tflite文件了。
3.2 開發APP
此處我們直接使用位於tensorflow/tensorflow/contrib/lite/java/demo中的例子。該樣例編譯後的APP執行效果為識別攝像頭拍攝到的畫面中的物品,效果如圖:
該項目主要有四個java代碼文件:
1.AutoFitTextureView.java
2.CameraActivity.java
3.Camera2BasicFragment.java
4.ImageClassifier.java
前兩個很簡單,CameraActivity.java是一個activity類,其中包含了一個Carama2BasicFragment。AutoFitTextureView則是提供了一個自動適應屏幕的攝像頭預覽View。
Camera2BasicFrgment.java則是整個APP的主體,其實現了UI界面,並且使用classifyFrame()方法周期性地進行圖像識別。
privateRunnable periodicClassify =
newRunnable() {
@Override
publicvoidrun(){
synchronized(lock) {
if(runClassifier) {
classifyFrame();
}
}
backgroundHandler.post(periodicClassify);
}
};
classifyFrame()的代碼中可以看出它是從AutoFitTextureView中提取圖片信息,保存為bitmap,並將其通過classifyFrame(bitmap)方法傳遞給ImageClassifier進行內容識別,然後返回識別的結果。
privatevoidclassifyFrame(){
if(classifier ==null|| getActivity() ==null|| cameraDevice ==null) {
showToast("Uninitialized Classifier or invalid context.");
return;
}
Bitmap bitmap =
textureView.getBitmap(ImageClassifier.DIM_IMG_SIZE_X, ImageClassifier.DIM_IMG_SIZE_Y);
String textToShow = classifier.classifyFrame(bitmap);
bitmap.recycle();
showToast(textToShow);
}
ImageClassifier(Activity activity)throwsIOException {
tflite =newInterpreter(loadModelFile(activity));
labelList = loadLabelList(activity);
imgData =
ByteBuffer.allocateDirect(
DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE);
imgData.order(ByteOrder.nativeOrder());
labelProbArray =newbyte[1][labelList.size()];
Log.d(TAG,"Created a Tensorflow Lite Image Classifier.");
}
StringclassifyFrame(Bitmap bitmap){
if(tflite ==null) {
Log.e(TAG,"Image classifier has not been initialized; Skipped.");
return"Uninitialized Classifier.";
}
convertBitmapToByteBuffer(bitmap);
// Here"s where the magic happens!!!
longstartTime = SystemClock.uptimeMillis();
tflite.run(imgData, labelProbArray);
longendTime = SystemClock.uptimeMillis();
Log.d(TAG,"Timecost to run model inference: "+ Long.toString(endTime - startTime));
String textToShow = printTopKLabels();
textToShow = Long.toString(endTime - startTime) +"ms"+ textToShow;
returntextToShow;
}
4 .模型文件的提取與還原
4.1 Tensorflow Lite APP
我們將這個官方樣例APP的APK解包,然後在assets目錄下找到了該.tflite文件。
由於toco工具並不是單向轉化的,它還可以將.tflite文件轉化為.pb文件。因此,我們可以再次利用toco工具獲得包含圖信息與參數信息的.pb文件。運行如下命令:
./toco --input_file=./target_in_your_app.tflite --output_file=test2.pb --input_format=TFLITE --output_format=TENSORFLOW_GRAPHDEF --input_shape=[1,224,224,3] --input_array=conv1 --output_array=softmax_linear
需要注意的是,這些參數對於APP的逆向分析者來說並不是現成的,需要仔細查看反編譯的代碼,從中找到這些信息。否則toco運行將失敗。
將該APK放入JADX等工具中反編譯後,在如下部分找到了所需轉換的信息。
那麼該如何從.pb文件中獲取能被我們輕易理解的訓練模型信息呢?使用tensorboard即可做到。首先利用如下腳本可以將.pb中的信息提取並保存到指定目錄下:
importtensorflowastf
fromtensorflow.python.platformimportgfile
withtf.Session()assess:
withtf.gfile.FastGFile("/path/to/the/file.pb","rb")asf:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
tf.import_graph_def(graph_def, name="")
writer = tf.summary.FileWriter("/path/you/want", sess.graph)
writer.close()
然後輸入命令:
輸出中包括一個url,在瀏覽器中訪問這個地址,便可以在相關項目頁面中看到該模型的詳細信息了。下圖便是tensorboard最後顯示的模型。
4.2 Tensorflow APP
在/tensorflow/tensorflow/examples/android目錄下還有一個樣例APP,它沒有使用Tensorflow Lite,而是通常Tensorflow。該APP的功能源碼此處不再展開分析,直接來看一下其關鍵部分的代碼。
從AndroidManifest.xml中可以看出,該APP安裝後會出現四個圖標,各自對應四個不同的Activity:
android:screenOrientation="portrait"
android:label="@string/activity_name_classification">
android:screenOrientation="portrait"
android:label="@string/activity_name_detection">
android:screenOrientation="portrait"
android:label="@string/activity_name_stylize">
android:screenOrientation="portrait"
android:label="@string/activity_name_speech">
進一步分析源碼,發現這個APP中的模型文件直接使用了固化參數後的.pb文件。如Stylize功能中使用TensorFlowInferenceInterface來獲取stylize_quantized.pb文件中的模型信息進行圖像處理。
privatestaticfinalString MODEL_FILE ="file:///android_asset/stylize_quantized.pb";
......
inferenceInterface =newTensorFlowInferenceInterface(getAssets(), MODEL_FILE);
......
inferenceInterface.feed(
INPUT_NODE, floatValues,1, bitmap.getWidth(), bitmap.getHeight(),3);
inferenceInterface.feed(STYLE_NODE, styleVals, NUM_STYLES);
inferenceInterface.run(newString[] , isDebug());
inferenceInterface.fetch(OUTPUT_NODE, floatValues);
......
在DetectorActivity中更是有三種物體檢測模型讓我們選擇:
privatestaticfinalString MB_MODEL_FILE ="file:///android_asset/multibox_model.pb";
......
privatestaticfinalString TF_OD_API_MODEL_FILE =
"file:///android_asset/ssd_mobilenet_v1_android_export.pb";
......
privatestaticfinalString YOLO_MODEL_FILE ="file:///android_asset/graph-tiny-yolo-voc.pb";
......
DetectorActivity的效果如下:
由此可知,要想獲取這類APP,需要提取其資源文件中的.pb文件。相比於Tensorflow Lite少了一個使用toco工具將.tflite轉化回.pb的步驟。有了.pb文件後,便和上文中使用tensorboard的方式一樣,對其內部內容進行可視化分析。
5. 總結
從上文中可以看出Tensorflow Lite會將訓練模型的圖信息與參數信息幾乎完全加入到APK中,我們可以從其APK中提取並理解該人工智慧模型的實現細節。因此,對於一些涉及敏感商業機密的人工智慧模型,廠商在使用Tensorflow+Anroid的開發方案前需要謹慎衡量一下其所可能泄露的技術與帶來的風險。
對於希望保護自身知識產權的組織,也可以從上文看出一些可以用來防禦的點。第一是通過一些資源保護的手段來使得分析人員無法獲取.tflite或.pb文件。第二是當使用Tensorflow Lite時,可以通過一些代碼保護技術來使得他人難以獲得正確的toco所需參數。
因此,個人認為可以對圖參數文件進行加密,或是選用一些不僅僅是保護dex,而且對資源文件也有較高保護技術的加固產品。
TAG:銀河安全實驗室 |