/bin/bash^M: bad interpreter: No such file or directory

执行一个脚本full_build.sh 时, 一直是提示我:

-bash: ./full_build.sh: /bin/bash^M: bad interpreter: No such file or directory

 

开始是说我权限不够, 不能执行, 接着我就把权限给改了,  就一直报上面问题.

记得几个月前, 就遇到过类似的问题, 当时是在编译Android Framework, 后来打开出错的.xml文件, 很直接的看到很多的^M的标识,  由于负责编译的同事帮忙解决了, 就没有去问为什么, 今天再次遇到, 就上网搜了搜, 才明白了原因.

 

出现上面错误的原因之一是脚本文件是DOS格式的, 即每一行的行尾以\r\n来标识, 使用vim编辑器打开脚本, 运行:

:set ff?

可以看到DOS或UNIX的字样. 使用set ff=unix把它强制为unix格式的, 然后存盘退出, 即可.

 

网上也有很多的其他方法, 比如: 执行dos2unix 命令转换编码,   命令为: #dos2unix full_build.sh,  但我没有dos2unix的安装包, 所以就跳过了.

 

也有说造成这种问题的原因是在使用vim时不小心按了个: Ctrl+v,  脚本是我从服务器上下的, 不清楚到底怎么会变成了DOS格式的了. 总之解决了就行啦.

 

转自:

http://blog.csdn.net/esther0401/article/details/7361496

GDB调试器的使用

  默认情况下,gcc/g++编译的可执行文件是不包含调试信息的,GDB是一个源代码级的调试器,使用GDB调试程序需要程序的源代码、符号及其对应的行号等,其中符号和行号可以是单独的文件,亦可以在编译时嵌入到可执行文件中。使用gcc/g++时使用-g选项即可将必要的调试信息包含到可执行文件中,使用-g3选项还可以将源代码中的宏信息也包含进去。
另外,调试过程中需要随时查看源代码,但源代码并没有包含到可执行文件中。通常GDB在当前目录查找源文件,但某些情况下(比如调试系统命令)需要手动指明源代码的查找目录,directory ~向GDB指明到$HOME下查找源文件。
启动GDB的启动很灵活,它的各种特性,你可以在Shell下通过选项和参数指定,也可以在GDB启动之后在GDB自己的命令行下使用GDB内置的命令来指定。最常用的是直接使用命令gdb PROGRAM启动,这样gdb自动加载符号表等调试信息。若要向被调试程序传递参数,可以采用gdb –args program ARG1 ARG2的形式,其中–args(或者-args)是必须的,它告诉GDB该选项之后已经没有GDB需要的选项了。另外,还可以直接使用gdb启动,然后使用file program加载调试信息。此时若要设置被调试程序的参数,可以使用set命令的args子命令,如set args ARG1 ARG2. 还有一种传递参数的方法,在下面介绍。
断点调试程序,就是使用调试器(Debugger)通过检测和改变被调试程序(Debuggee)的状态、控制其执行的方式找出被调试程序中的错误和潜在的bug。调试程序,观察程序当前的行为的前提是让程序在“适当的时候”暂停运,那么什么是适当的时候呢?使用GDB时,让程序暂停运行需要使用断点。具体地,断点又可以分为普通断点(breakpoint以下简称断点),观察点(watchpoint),捕捉点(watchpoint)三类。
普通断点使用break命令(简写为b)设置。break命令的格式为break [bp-spec] [if CONDITION] [thread THREADNUM],bp-spec指明断点设置的位置,可以是行号、函数名或者指令地址,如果bp-spec省略,则断点被设置在程序所要执行的下一行代码(或者指令)上。if CONDITION指明当程序到达bp-spec位置时,只有CONDITION条件成立时程序才会暂停。thread THREADNUM用在多线程程序的调试中,断点只被设置在指定的线程号(GDB内部而不是系统使用的标号)为THREADNUM的线程上,如果THREADNUM为all则所有线程都会被设置断点。补充下bp-spec可以是函数名b FUNCTIONNAME(重载函数名需要使用”包含才能自动补全),可以是行号b LINENUMBER或者b FILENAME:LINENUMBER,还可以是指令地址b *ADDRESS。另外,break命令还有其它一些变种,比如tbreak设置临时断点,被使用一次就会自动删除,rbreak使用正则表达式来指明函数名。
观察点使用watch命令,命令格式与break相同,但它并不是指明断点的位置,而是指明一个表达式,每当该表达式的值改变时,程序便会被暂停。表达式可以是某个变量、由若干变量组成的表达式或者内存地址。
捕捉点是另一种断点,它使用某种事件的发生作为触发条件,命令各式为catch EVENT。这些事件主要包括异常的抛出和捕获(catch throw/catch)和某个系统调用(catch fork/open/exec, catch syscall CALLNUM)。
查看当前的断点设置情况可以使用breakpoints,也可以使用info breakpoints(或者简写为i b)命令,查看某个断点使用breakpoints bpnum,bpnum为断点号。
使用enable/disable bpnum使某个断点生效和失效,delete bpnum删除断点。bpnum还可以是一个范围,以此批量操作断点,比如d 2-6删除断点2到6。
使用ignore bpnum COUNT还可以使某个断点被或略COUNT次,即是说断点bpnum的前COUNT次到达都不会被触发,知道COUNT递减至0。另外,在COUNT递减至0之前,该断点上的条件是不会被考虑的。
CONDITION bpnum [if condition],修改bpnum上的触发条件,若if被省略,则bpnum断点上的条件将被删除。
运行

GDB启动和加载调试信息后,被调试程序并没有运行。使用run/r或者start命令,GDB建立子进程来运行被调试程序。run和start命令稍有不同,即run仅仅加载程序然后运行,而start会在程序的入口函数(main)设置一个临时断点,程序运行到那里就会暂停,临时断点也随即被清除。另外run和start命令后面都可以加上传递给被调试程序的参数,若不加参数则使用GDB启动时传递的参数或者使用set args命令设置的参数。若要清除参数而不退出GDB,使用不带参数的set args即可。
其它运行相关的命令还有

continue/c,继续运行。
next/n, 下一行,且不进入函数调用
stop/s, 下一行,但进入函数调用
ni或者si, 下一条指令,ni与si的区别同n与s的区别
finish/fini, 继续运行至当前栈帧/函数刚刚退出
until/u, 继续运行至某一行,在循环中时,u可以实现运行至循环刚刚退出,但这取决于循环的实现。

查看

调试的主要工作,我想就是检查程序的状态吧,内存的状态,程序的流程,指令的安排。GDB有多个命令来查看程序的状态,最常用的是list/l, print/p和x和disassemble。

list linenum/function列出第linenum行或者function所在行附近的10行,list *address列出地址address附近的10行。
list列出上一次list命令列出的代码后面的10行
list -,列出上一次list命令列出的代码前的10行
list列出的默认行数可由set listsize size来设置
p /fmt VARIABLE根据fmt指定的格式打印变量VARIABLE的值,常用的fmt有d(decimal), u(unsigned), x(hex), o(octal), c(character), f(float), s(string)
x /nfs ADDRESS是我最喜欢的命令,它显示ADDRESS地址开始的内容,形式由nfs指定。其中n为次数(个数),f是格式,除p命令可以使用的格式外,还可以使用i(instruction)打印指令,s为所打印内容的大小,可以是b(byte), h(half word), w(word, 4bytes), g(8bytes). nfs均可省略,若省略则使用最近一次使用x命令时的值,最初nfs是1dw。
disassemble /[r][m] [ADDRESS]将ADDRESS所在函数进行反汇编,ADDRESS也可以是一个由行号组成的区间。不指定任何选项时disas只简单的列出反汇编指令,指定m(mixed)选项时会对应地列出指令和源代码,指定r(raw)时会打印出指令对应的十六进制编码。

退出

Ctrl-C会终止当前调试的程序(而不是调试器)。q(quit)退出GDB,若退出时被调试程序尚未结束,GDB会提示,请求确认。
其它
help

使用GDB的过程中,如果对某一个命令的用法不清楚,可以随时使用help/h寻求帮助。
info

info/i命令也是一个十分常用的GDB命令,可以查看许多信息。

i program查看被调试程序的运行状态,如进程号、ip(指令指针)、是否运行、停止原因等。
i b [bpnum]查看断点
i f [frame-num]查看当前(或指定)栈帧,i f all还会列出当前栈帧的局部变量
i line LINENUM查看代码行LINENUM,打印其指令地址,此命令后执行x/i可查看该地址处的指令,然后回车即可继续向后查看接下来的指令
i reg查看寄存器状态,i all-reg查看包含浮点堆栈寄存器在内的所有寄存器情况
i args查看当前栈帧的参数
i s追踪栈帧信息,相当于backtrace/bt命令
i threads查看当前进程的线程信息

回到过去

跟踪调试程序的过程中,偶尔会错过一些关键点,不得不重新启动程序。如果错过的这些关键点不容易再现,就更令人懊恼了。GDB提供一种机制可以让你将程序向后调整,重新来过。这种机制叫做checkpoint,你可以在程序运行的关键点处执行checkpoint命令,你将得到一个数字(check-num)来标识这个checkpoint。在以后的某个时刻使用restart check-num将程序回滚到设置该checkpoint的时刻,而此时此刻的“内存状态”恰如彼时彼刻,你可以重新调试这段程序(比如设置不同的变量值来测试不同的情况)。但覆水难收的道理你是懂得,回滚的这段程序之间产生的内存之外的效应是无法恢复的,比如写出到文件的数据收不回来了(但文件的指针偏移是可以恢复的,因为它的值保存在内存),通过网络发出的数据就更要不回来了。
使用i checkpoints可以查看checkpoint信息,比如check-num及其所处代码行。
据我揣测,GDB的这种“回到过去”的伎俩并不是逐步撤销之前运行的指令,而是在checkpoint命令执行的时候,把被调试程序fork/clone了。
多线程

调试多线程程序与普通程序没有太大的区别。

i threads查看当前进程包含的线程的信息,包括线程号及其GDB内部标识号,当前处于前端的线程。
thread thread-num切换到线程thread-num
set scheduler-locking [on|off|step],这是一个比较重要的选项,它控制这当前调试线程与其它线程的执行关系。设置为on时,其它线程不会抢占当前线程。设置为off(默认)时,当前线程执行时随时可能被其它线程抢占。设置为step时,在执行step命令时不会被抢占,但使用next跳过函数调用时可以/可能会被抢占,即调度器会被执行。

技巧

回车。在GDB命令行下,简单的回车会执行上一个命令。而且GDB命令中可以使用回车重复执行的都是有记忆的,如果使用回车,该命令就会根据上一次的执行适当地调整参数重复执行。比如使用l func列出函数func附近的10行代码,接着回车就会打印接下来的10行。使用x/16xw ADDRESS以16进制形式查看ADDRESS处的16个字,接着回车就会以同样的格式打印接下来的16个字。如果你已经set $i=0了,那么通过p a[$i++]然后一直回车就可以依次打印数组a的元素了。x/i $eip打印下一条指令,接着回车就会打印下下一条指令,以此类推。但,有的指令是无法使用回车来重复执行的,比如run/start,总之,通常,你觉得不能/不适合重复执行的命令就无法重复执行。
命令简写,有的命令名称较长甚至很长,但GDB允许用户只使用足以区别其它命令的前几个字符来执行命令,当然你也可以使用TAB自动补全。另外一些极为常用的命令有专门的简写形式,通常只有一个字母,例如break/b, list/l, info/i, continue/c, next/n, step/s, nexti/ni, stepi/si, frame/f, print/p等等等等。
在GDB中可以自定义变量(仅供GDB内部使用),很多时候可以方便查看一些表达式的值。有的时候使用变量似乎是必须的,比如x *($esp)是不合法的,因为GDB不允许对寄存器变量进行解引用(dereference, but why?)。这时,设置变量set $p=*($esp),然后x $p就可以了。

这只是一个小小的不完全的总结,如果你从未使用过GDB,推荐使用RMS的《Debugging with GDB》学习,还有一本小书《GDB Pocket Reference》,不妨做你的调试菜谱,如果你喜欢GDB的话。

用python ctypes调用动态链接库

ctypes is very cool! Great piece of work.
– Just van Rossum

ctypes使得python能够直接调用c语言开发的动态链接库,非常强大。
为了使用CTypes,你必须依次完成以下步骤:
* 编写动态连接库程序
* 载入动态连接库
* 将Python的对象转换为ctypes所能识别的参数
* 使用ctypes的参数调用动态连接库中的函数

来个简单的实例吧:

1. 编写动态链接库

C代码  收藏代码
  1. // filename: foo.c
  2. #include <stdio.h>
  3. char* myprint(char *str)
  4. {
  5.     puts(str);
  6.     return str;
  7. }
  8. float add(float a, float b)
  9. {
  10.     return a + b;
  11. }

以上foo.c代码,linux下编译为动态链接库文件,命令是:

Shell代码  收藏代码
  1. gcc -fPIC -shared foo.c -o foo.so

2. ctypes调用

Python代码  收藏代码
  1. #!/usr/bin/env python
  2. # FILENAME: foo.py
  3. from ctypes import *
  4. foo = CDLL(‘./foo.so’)
  5. myprint = foo.myprint
  6. myprint.argtypes = [POINTER(c_char)] # 参数类型,为char指针
  7. myprint.restype = c_char_p # 返回类型,同样为char指针
  8. res = myprint(‘hello’)
  9. print res
  10. add = foo.add
  11. add.argtypes = [c_float, c_float] # 参数类型,两个float(c_float内ctypes类型)
  12. add.restype = c_float
  13. print add(1.3, 4.2)

文档请参考http://docs.python.org/library/ctypes.html

3. 查找链接库

Python代码  收藏代码
  1. >>> from ctypes.util import find_library
  2. >>> find_library(“m”)
  3. ‘libm.so.6’
  4. >>> find_library(“c”)
  5. ‘libc.so.6’
  6. >>> find_library(“bz2”)
  7. ‘libbz2.so.1.0’
  8. >>>

调用libc里的printf:

Python代码  收藏代码
  1. #filename: printf_example.py
  2. import ctypes
  3. from ctypes.util import find_library
  4. printf = ctypes.CDLL(find_library(“c”)).printf
  5. printf(“hello, world\n”)

引用自: http://willzh.iteye.com/blog/486075

python 调用so dll动态链接库

ctypes使得python能够直接调用c语言开发的动态链接库,非常强大。
为了使用CTypes,你必须依次完成以下步骤:
* 编写动态连接库程序
* 载入动态连接库
* 将Python的对象转换为ctypes所能识别的参数
* 使用ctypes的参数调用动态连接库中的函数

一、Windows下使用Python的ctypes调用Dll动态链接库

    1. 编写dll文件

打开VS2008,新建一个VC工程,选择Win32类型,Win32项目,用程序类型选择DLL………
调用方式见Linux调用方式。

二、Linux下使用Python的ctypes调用so动态链接库

    1. 编写so文件
1 //test.h
2 #include   “stdio.h”
3
4 void test();
5 float add(float, float);
01 //test.c
02 #include “test.h”
03
04 void test()
05 {
06     printf(“Hello Dll…\n”);
07 }
08
09 float add(float a, float b)
10 {
11     return a + b;
12 }
1 gcc -fPIC -shared test.c -o libtest.so
2
3 #-fPIC  编译成位置无关代码,必须  不然你的程序在别的地方肯可能运行不了
4 #-shared  当然是说要编译成共享库了
    1. Python调用so动态链接库
01 #!/usr/bin/env python
02 # -*-coding:UTF-8-*-
03
04 print “sss”
05
06 from ctypes import *
07
08 test = cdll.LoadLibrary(“./libtest.so”)
09
10 test.test()
11
12 add = test.add
13 add.argtypes = [c_float, c_float] # 参数类型,两个float(c_float内ctypes类型)
14 add.restype = c_float
15
16 print add(1.2, 19.2)

发的

肖梓航:Andriod安全漏洞将长期存在

摘要:肖梓航表示,国内外有很多设备厂商会对内核、系统引导做相应修改,加入自己的驱动代码,设置和软件。这些代码里有大量提权问题。虽然Google会去对第三方代码来进行审查,并将补丁推送给厂商,但这些厂商并不一定会把补丁打上,也不一定及时推送给用户,进一步加重了Android平台的碎片化。如此复…

 

内容简介:肖梓航在演讲中分析了Android漏洞的攻防趋势。在漏洞方面,Android平台面临5大问题:碎片化和硬件厂商对安全漏洞的忽视,1day问题和设备上代码成为提权漏洞的新来源;系统和框架漏洞大量出现;应用软件自动化漏洞挖掘遭遇方法瓶颈;恶意代码利用系统和软件漏洞的高级攻击;APT攻击趋势下,信息泄露型漏洞更重要。同时,肖梓航给出了Android软件保护的趋势:软件盘全攻击点从代码转向数据和业务;恶意代码开始采用商业级代码保护技术;代码运行时修改技术可能使软件保护方案出现突破。
原始链接:

http://www.csdn.net/article/a/2013-10-10/15816786

从CERT.RSA中提取证书

AndroidMETA-INFX509keytool

目录(?)[+]

原文链接:http://www.wangchen.org/2011/01/%E4%BB%8Ecert-rsa%E4%B8%AD%E6%8F%90%E5%8F%96%E8%AF%81%E4%B9%A6/

 

Apk 包中的META-INF目录下,有一个CERT.RSA,它是一个PKCS7 格式的文件。

下面介绍几种从中获取证书的方法。

Linux command line

[plain] view plaincopy

  1. openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs -text

你可以得到一个文本输出:

 

[plain] view plaincopy

  1. Certificate:
  2.     Data:
  3.         Version: 3 (0x2)
  4.         Serial Number: 1281971851 (0x4c69568b)
  5.         Signature Algorithm: sha1WithRSAEncryption
  6.         Issuer: CN=Michael Liu
  7.         Validity
  8.             Not Before: Aug 16 15:17:31 2010 GMT
  9.             Not After : Aug 10 15:17:31 2035 GMT
  10.         Subject: CN=Michael Liu
  11.         Subject Public Key Info:
  12.             Public Key Algorithm: rsaEncryption
  13.             RSA Public Key: (1024 bit)
  14.                 Modulus (1024 bit):
  15.                     00:8d:04:84:a2:1e:c6:56:39:f2:cd:a6:f0:48:a5:
  16.                     f7:5e:71:8f:e1:a8:af:a7:dc:66:92:a2:b9:cf:da:
  17.                     0f:32:42:ce:83:fe:bc:e1:4f:0a:fd:d9:a8:b3:73:
  18.                     f4:ff:97:15:17:87:d6:d0:3c:da:01:fc:11:40:7d:
  19.                     04:da:31:cc:cd:da:d0:e7:7b:e3:c1:84:30:9f:21:
  20.                     93:95:20:48:b1:2d:24:02:d2:b9:3c:87:0d:fa:b8:
  21.                     e1:b1:45:f4:8d:90:0a:3b:9d:d8:8a:9a:96:d1:51:
  22.                     23:0e:8e:c4:09:68:7d:95:be:c6:42:e9:54:a1:5c:
  23.                     5d:3f:25:d8:5c:c3:42:73:21
  24.                 Exponent: 65537 (0x10001)
  25.     Signature Algorithm: sha1WithRSAEncryption
  26.         78:3c:6b:ef:71:70:55:68:28:80:4d:f8:b5:cd:83:a9:01:21:
  27.         2a:c1:e4:96:ad:bc:5f:67:0c:cd:c3:34:51:6d:63:90:a9:f9:
  28.         d5:5e:c7:ef:34:43:86:7d:68:e1:99:87:92:86:34:91:6d:67:
  29.         6d:b2:22:e9:5e:28:aa:e8:05:52:04:6e:4e:d4:7f:0f:b0:d6:
  30.         28:f5:2b:11:38:d5:15:cb:e3:e4:c9:99:23:c1:84:4f:ce:69:
  31.         e9:b1:59:7b:8e:30:01:1c:e1:92:ee:0d:54:61:29:f5:8e:9e:
  32.         42:72:26:2b:aa:c7:af:d9:c9:d1:85:95:8e:4c:8d:5c:77:c5:
  33.         ce:4e

 

Java

这是最简单的

 

  1. import sun.security.pkcs.PKCS7;
  2. import java.io.FileInputStream;
  3. import java.io.IOException;
  4. import java.security.cert.CertificateException;
  5. import java.security.cert.X509Certificate;
  6. public class Test {
  7.     public static void main(String[] args) throws CertificateException, IOException {
  8.         FileInputStream fis = new FileInputStream(“/Users/wangchen/Desktop/CERT.RSA”);
  9.         PKCS7 pkcs7 = new PKCS7(fis);
  10.         X509Certificate publicKey = pkcs7.getCertificates()[0];
  11.         System.out.println(“issuer1:” + publicKey.getIssuerDN());
  12.         System.out.println(“subject2:” + publicKey.getSubjectDN());
  13.         System.out.println(publicKey.getPublicKey());
  14.     }
  15. }

 

使用openssl-dev 的C API

  1. #include <openssl/bio.h>
  2. #include <openssl/x509.h>
  3. #include <openssl/pkcs7.h>
  4. #include <string>
  5. #include <iostream>
  6. using namespace std;
  7. string to_string(X509_NAME* name)
  8. {
  9.     BIO* mem = BIO_new(BIO_s_mem());
  10.     if (mem == NULL)
  11.         return NULL;
  12.     if (X509_NAME_print_ex(mem, name, 0, XN_FLAG_RFC2253) < 0)         return NULL;     string str;     char buf[128];     while((BIO_gets(mem, &buf[0], sizeof(buf))) > 0)
  13.     {
  14.         str.append(buf);
  15.     }
  16.     BIO_free(mem);
  17.     return str;
  18. }
  19. int main()
  20. {
  21.     FILE* fp;
  22.     if (!(fp = fopen(“CERT.RSA”, “rb”)))
  23.     {
  24.         fprintf(stderr, “Error reading input pkcs7 file\n” );
  25.         exit(1);
  26.     }
  27.     /* todo: 这里可能有内存漏洞,有空查一下文档 */
  28.     PKCS7* pkcs7 = d2i_PKCS7_fp(fp, NULL);
  29.     X509* cert = sk_X509_pop(pkcs7->d.sign->cert);
  30.     string subject = to_string(X509_get_subject_name(cert));
  31.     string issuer = to_string(X509_get_issuer_name(cert));
  32.     char *modulus = BN_bn2dec(X509_get_pubkey(cert)->pkey.rsa->n);
  33.     cout << subject << endl;
  34.     OPENSSL_free(modulus);
  35.     fclose(fp);
  36.     return 0;
  37. }

Python

我没在Python 2.x 的OpenSSL 库中找到从PKCS7中提取证书的方法……
看来无奈时刻只能自己做Binding了。

GDB全解

<1>.GDB调试教程

用GDB调试程序(一)

用GDB调试程序(二)

用GDB调试程序(三)

用GDB调试程序(四)

用GDB调试程序(五)

用GDB调试程序(六)

用GDB调试程序(七)

<2>. 定制ARM上的GDB调试器

http://hi.baidu.com/dos2004/item/ceec49a21da256db5af191cf

arm-linux-gdb+gdbserver环境搭建以及远程调试

————————————————

gdbserver远程调试是在嵌入式LINUX上调试应用程序的优秀手段之一,熟悉PC LINUX上GDB调试的人肯定非常乐于使用此种调试方法。至于GDB调试的优越性,非此篇的话题,于此不表。
gdb源码下载:http://ftp.gnu.org/gnu/gdb/
我的环境:gcc : 3.4.2
arm-linux-gcc : 3.4.1
下载GDB源码: 6.6
nfs共享目录: ~/tftpboot
主机IP:192.168.1.200   板子IP:192.168.1.168

1.编译arm-linux-gdb
$cd gdb-6.6
$./configure --target=arm-linux --prefix=/usr/local/arm/gdb -v
target指明编译生成的GDB用于调试ARM-LINUX程序,prefix指明安装目录
$make
#make install
#vi /etc/profile
export PATH=$PATH:/usr/local/arm/gdb/bin    --把arm-linux-gdb加入环境变量

2.编译gdbserver
$cd gdb/gdbserver
$
./configure --target=arm-linux --host=arm-linux
target含义同前,host指明编译生成的gdbserver运行在arm-linux上,前者没有设定host的原因是
arm-linux-gdb是在pc linux上运行的,就像arm-linux-gcc (很好理解的:))
$
make CC=/usr/local/arm/3.4.1/bin/arm-linux-gcc
其实这里也可以make CC=arm-linux-gcc,因为有的系统这要可能不行,我的是行的.
$cp gdbserver ~/tftpboot
~/tftpboot是我的NFS共享目录,目的是要把gdbserver下载到板子上

3.拷贝libthread库(如果运行gdbserver出错的话)
$cd /usr/local/arm/3.4.1/arm-linux/lib
$cp libthread_db-1.0.so ~/tftpboot

4.下载gdbserver到板子上,启动minicom
#mount -t nfs -o wsize=256,rsize=256 192.168.1.200:/home/lua/tftpboot /mnt/nfs
#cd /mnt/nfs
#cp gdbserver /usr/bin/
#cp libthread_db-1.0.so /lib/
#ln -s /lib/libthread_db-1.0.so /lib/libthread_db.so.1
#ln -s /lib/libthread_db-1.0.so /lib/libthread_db.so
就此准备工作做好了,*_*

5.调试示例
1 #include<stdio.h>
2
3 int main()
4 {
5     char *ptr = “csdn”;
6     printf(“%c\n”,*(ptr++));
7     return 0;
8 }
上面这段代码记为test.c,用arm-linux-gcc -g test.c -o test编译,再把生成的test文件复制到~/tftpboot
minicom下:
#cd /mnt/nfs
#gdbserver 192.168.1.200:7777 test
Process test created; pid = 842
Listening on port 7777

主机shell下
$cd ~/tftpboot
$arm-linux-gdb test
GNU gdb 6.6
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details.
This GDB was configured as “–host=i686-pc-linux-gnu –target=arm-linux”…
(gdb)
注意一下显示信息的最后–host=i686-pc-linux-gnu –target=arm-linux,明白了吧。。。
target remote 192.168.1.168:7777   –连接gdbserver
Remote debugging using 192.168.1.168:7777
0x40000dd0 in _start () from /lib/ld-linux.so.2
表示连接上了服务器,:),接下来就可以调试了。arm-linux-gdb和GDB的用法一样,只是没有r这个命
令,运行程序用c命令。
(gdb) l
1       #include<stdio.h>
2
3       int main()
4       {
5               char *ptr = “csdn”;
6               printf(“%c\n”,*(ptr++));
7               return 0;
8       }
(gdb) b 3
Breakpoint 1 at 0x83d0: file test.c, line 3.

另外由于程序是在目标板上运行,调试是在PC下,程序的结果还是会在目标板上显示的,
例如:minicom,lcd等。
btw,附近一篇介绍GDB使用的文章:http://blog.csdn.net/haoel/archive/2003/07.aspx,这下全了吧。哈

 

 

利用ssh传输文件

在linux下一般用scp这个命令来通过ssh传输文件。

1、从服务器上下载文件
scp username@servername:/path/filename

例如scp root@192.168.0.101:/var/www/test.txt  把192.168.0.101上的/var/www/test.txt 的文件下载到当前目录

2、上传本地文件到服务器
scp /path/filename username@servername:/path

例如scp /var/www/test.php  root@192.168.0.101:/var/www/  把本机/var/www/目录下的test.php文件上传到192.168.0.101这台服务器上的/var/www/目录中

 

3、从服务器下载整个目录
scp -r username@servername:/var/www/local_dir/

例如:scp -r root@192.168.0.101:/var/www/test  /var/www/

4、上传目录到服务器
scp  -r local_dir username@servername:remote_dir
例如:scp -r test  root@192.168.0.101:/var/www/   把当前目录下的test目录上传到服务器的/var/www/ 目录

 

注:目标服务器要开启写入权限。

金山手机毒霸工作原理

本文章由Jack_Jia编写,转载请注明出处。
文章链接:
http://blog.csdn.net/jiazhijun/article/details/8804402

作者:Jack_Jia    邮箱: 309zhijun@163.com

 

一、序言

 

金山手机毒霸(http://m.duba.com/)是金山网络推出的首款Android APP行为管理软件,是首家拦截软件恶意广告、智能防御病毒行为、查杀最新病毒和自主管理高危隐私权限的安卓手机安全管理软件。

它具有如下特色功能:

1、有效清除软件内置广告,拦截软件恶意广告。

2、依托于首创的Java虚拟机拦截技术,更精准更深入的拦截APP的高危行为。

本文将对金山手机毒霸的进行简单的逆向分析,以达到了解其工作原理的目的。金山手机毒霸的最新版本为V2.0,但为了使我们的分析过程简单高效,我们特意选择金山手机毒霸V1.0Beta版本作为分析样本。博友可以通过如下链接下载(http://bbs.xda.cn/thread-11186508-1-1.html)。

 

二、基本信息

 

1、安装包关键路径文件信息

 

lib\srmeabi\:

res\raw :

其中ksremote.mp3、libksrootclient.mp3、rootkeeper.mp3通过后缀名伪装成mp3文件,其实这三个文件为jar包。

 

AndroidMainfest.xml:

 

  1. <application android:theme=”@style/MainStyle” android:label=”@string/app_name_desktop” android:icon=”@drawable/main_icon_big” android:name=”com.ijinshan.duba.main.MobileDubaApplication” android:allowClearUserData=”false” android:debuggable=”false”>
  2.     <activity android:label=”@string/app_name” android:name=”com.ijinshan.duba.main.MainActivity” android:launchMode=”singleTask” android:screenOrientation=”portrait” />
  3.     <activity android:name=”com.ijinshan.duba.main.SplashActivity” android:clearTaskOnLaunch=”true” android:launchMode=”singleTop” android:screenOrientation=”portrait”>
  4.         <intent-filter>
  5.             <action android:name=”android.intent.action.MAIN” />
  6.             <category android:name=”android.intent.category.LAUNCHER” />
  7.         </intent-filter>
  8.     </activity>
  9.     <activity android:name=”com.ijinshan.duba.main.AuthorityActivity” android:screenOrientation=”portrait” />
  10.     <activity android:name=”com.ijinshan.duba.AdUI.AdwareNotifyListActivity” android:screenOrientation=”portrait” />
  11.     <activity android:name=”com.ijinshan.duba.AdUI.AdPrivacyActivty” android:screenOrientation=”portrait” />
  12.     <activity android:name=”com.ijinshan.duba.AdUI.AdScanActivty” android:screenOrientation=”portrait” />
  13.     <activity android:name=”com.ijinshan.duba.AdUI.AdwareLogActivty” android:screenOrientation=”portrait” />
  14.     <activity android:name=”com.ijinshan.duba.AdUI.AdDetailActivty” android:screenOrientation=”portrait” />
  15.     <activity android:name=”com.ijinshan.duba.common.NotifyEntryActivity” android:screenOrientation=”portrait” />
  16.     <activity android:name=”com.ijinshan.duba.malware.MalwareActivity” android:screenOrientation=”portrait” />
  17.     <activity android:name=”com.ijinshan.duba.malware.ScanResultListActivity” android:screenOrientation=”portrait” />
  18.     <activity android:name=”com.ijinshan.duba.malware.VirusDetailActivity” android:screenOrientation=”portrait” />
  19.     <activity android:name=”com.ijinshan.duba.defend.defendActivityTest” android:screenOrientation=”portrait” />
  20.     <activity android:name=”com.ijinshan.duba.privacy.PrivacyActivity” android:screenOrientation=”portrait” />
  21.     <activity android:name=”com.ijinshan.duba.privacy.PrivacyDetailActivity” android:screenOrientation=”portrait” />
  22.     <activity android:name=”com.ijinshan.duba.privacy.PrivacySortActivity” android:screenOrientation=”portrait” />
  23.     <activity android:theme=”@style/DialogActivityStyle” android:name=”com.ijinshan.duba.malware.PcConnectActivity” android:launchMode=”singleInstance” android:screenOrientation=”portrait”>
  24.         <intent-filter>
  25.             <action android:name=”” />
  26.         </intent-filter>
  27.     </activity>
  28.     <activity android:theme=”@style/DialogActivityStyle” android:name=”com.ijinshan.duba.watcher.FileInstNoticeActivity” android:launchMode=”singleInstance” android:screenOrientation=”portrait” />
  29.     <activity android:theme=”@style/DialogActivityStyle” android:name=”com.ijinshan.duba.watcher.AppLaunchMonitorActivity” android:launchMode=”singleInstance” android:screenOrientation=”portrait” />
  30.     <activity android:name=”com.ijinshan.duba.malware.BadNetActivity” android:screenOrientation=”portrait” />
  31.     <activity android:name=”com.ijinshan.duba.main.ShowProtocolActivity” android:screenOrientation=”portrait” />
  32.     <activity android:name=”com.ijinshan.duba.defend.Activity.IngnoreAppActivity” android:screenOrientation=”portrait” />
  33.     <activity android:theme=”@style/DialogActivityStyle” android:name=”com.ijinshan.duba.main.ShowRestartTipDialog” android:launchMode=”singleInstance” android:screenOrientation=”portrait” />
  34.     <service android:name=”com.ijinshan.duba.service.PcConnectService”>
  35.         <intent-filter>
  36.             <action android:name=”” />
  37.         </intent-filter>
  38.     </service>
  39.     <service android:name=”com.ijinshan.duba.defend.DefendService” android:exported=”false” android:process=”:DefendService” />
  40.     <receiver android:name=”com.ijinshan.duba.receiver.AutoRunReceiver” android:permission=”android.permission.RECEIVE_BOOT_COMPLETED” android:exported=”false”>
  41.         <intent-filter>
  42.             <action android:name=”android.intent.action.BOOT_COMPLETED” />
  43.             <category android:name=”android.intent.category.DEFAULT” />
  44.         </intent-filter>
  45.     </receiver>
  46.     <receiver android:name=”com.ijinshan.duba.receiver.ShutdownReceiver”>
  47.         <intent-filter>
  48.             <action android:name=”android.intent.action.ACTION_SHUTDOWN” />
  49.         </intent-filter>
  50.     </receiver>
  51.     <provider android:name=”com.ijinshan.duba.main.DubaConfigProvidor” android:exported=”false” android:authorities=”com.ijinshan.duba.config” />
  52.     <provider android:name=”com.ijinshan.duba.Provider.AdRuleProvidor” android:exported=”false” android:process=”:DefendService” android:authorities=”com.ijinshan.duba.adrule” />
  53.     <provider android:name=”com.ijinshan.duba.Provider.MalwareDBProvidor” android:exported=”false” android:process=”:DefendService” android:authorities=”com.ijinshan.duba.malwaredb” />
  54. </application>

 

 

2、手机毒霸运行时涉及进程及进程组件分布

 

通过对手机毒霸代码逆向分析及运行时进程状态变化,金山手机毒霸代码共在四类进程中被加载运行。

 

(1)com.ijinshan.duba 进程

 

广告扫描引擎、病毒扫描引擎、金山版本控制等逻辑都在该进程中运行,

另外手机毒霸还在15997端口建立监听,PC端可以通过该TCP连接发送命令手机端毒霸扫描。

 

(2)com.ijinshan.duba:DefendService进程

 

广告规则和扫描病毒信息由该进程通过Provider提供。

 

 

(2)com.ijinshan.duba.rootkeeper进程

该进程以ROOT身份运行,该进程提供了手机毒霸其它进程运行需要root身份才能执行的命令的Binder接口,第三方程序进程的代码注入由该进程完成。

 

 

(4)第三方(injected process)被注入程序进程

 

通过ptrace()注入到第三方程序的代码,ksremote.jar和libksrootclient.so完成java虚拟机hook和底层Socket hook。

 

 

三、JAVA虚拟机hook实现原理

目前Android进程代码的注入都是靠ptrace函数来完成。ptrace进程后完成底层函数的重定向。金山毒霸代码注入包括两部分:

 

1、底层C函数HOOK

2、JAVA虚拟机HOOK

 

代码注入基本流程如下:

 

1、com.ijinshan.duba.rootkeeper进程ptrace第三方进程,并注入libksrootclient.so文件

2、libksrootclient.so代码完成底层C函数hook并调用ksremote.jar代码,ksremote.jar完成java虚拟机hook

(1)C代码如何完成对java代码的调用呢?

 

基本代码实现如下:

 

  1. int (*callStatic)(const char* className, const char* methodName);
  2.        JavaVM* (*getJavaVM)();
  3.        JNIEnv* (*getJNIEnv)();
  4. void* handle = dlopen(“/system/lib/libandroid_runtime.so”, RTLD_NOW);
  5. getJNIEnv = dlsym(handle, “_ZN7android14AndroidRuntime9getJNIEnvEv”);
  6.        JNIEnv* env = getJNIEnv();
  7.        jclass classloaderClass = (*env)->FindClass(env,”java/lang/ClassLoader”);
  8.        jmethodID getsysloaderMethod = (*env)->GetStaticMethodID(env,classloaderClass<span style=”font-family: Arial, Helvetica, sans-serif;”> </span>, “getSystemClassLoader”, “()Ljava/lang/ClassLoader;”);
  9.        jobject loader = (*env)->CallStaticObjectMethod(env, classloaderClass, getsysloaderMethod);
  10.        jstring dexpath = (*env)->NewStringUTF(env, “dex文件路径”);
  11.        jstring dex_odex_path = (*env)->NewStringUTF(env,”odex文件路径”);
  12.        jclass dexLoaderClass = (*env)->FindClass(env,”dalvik/system/DexClassLoader”);
  13.        jmethodID initDexLoaderMethod = (*env)->GetMethodID(env, dexLoaderClass, “<init>”, “(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V”);
  14.        jobject dexLoader = (*env)->NewObject(env, dexLoaderClass, initDexLoaderMethod,dexpath,dex_odex_path,NULL,loader);
  15.        jmethodID findclassMethod = (*env)->GetMethodID(env,dexLoaderClass,”findClass”,”(Ljava/lang/String;)Ljava/lang/Class;”);
  16.        jstring javaClassName = (*env)->NewStringUTF(env,”加载类名”);
  17.        jclass javaClientClass = (*env)->CallObjectMethod(env,dexLoader,findclassMethod,javaClassName);
  18.        jmethodID start_inject_method = (*env)->GetStaticMethodID(env, adInjectClient_class, “调用方法名”, “()V”);
  19.        (*env)->CallStaticVoidMethod(env,javaClientClass,start_inject_method);

 

(2)java虚拟机hook如何实现呢?
java虚拟机hook都是通过java反射修改系统关键类的关键字段来实现的,我们通过替换LocationManager来看看如何实现的:

 

 

当用户代码运行ServiceManager.getService(“location”)的时候,得到就是手机毒霸的LocationManager了。

 

三、广告拦截原理

 

广告拦截逻辑大致包含以下几个方面:

1、Banner类型广告

当Activity显示的时候,手机毒霸遍历Activity View树,判断View类包名是否为广告平台包名,如果是则添加手机毒霸广告关闭图标,当用户点击关闭图标时,隐藏Banner          广告View。

2、WebView类型广告

判断WebViewClient类名判断是否为广告。

3、Notification类型广告

主要是通过RemoteViews的action来判断是否为广告。

 

另外手机毒霸通过hook Socket接口来完成广告的拦截,通过网络层的拦截来完成广告的拦截。

LBE 安全大师 V5.1 公测版不 root 也能卸载预装软件,是何原理?

朱向东大华电子做机器人

冯岩少许落寞褚利强 等人赞同
先回答提问者的问题。

众所周知,要卸载系统应用,需要 ROOT 权限。实际上,只是需要 system 文件夹的操作权限而已,ROOT 的第三方应用获取系统目录操作权限的最基本条件。到现在也是。

那我们来看一下 LEB 这次更新是通过什么手段来实现的不 ROOT 也可以卸载系统应用的。
新版 LEB 如果要解锁应用卸载的话,需要开启主动防御。主动防御有两种方式,免ROOT启动ROOT授权启动ROOT授权启动这里就不提了。我们来说一下免ROOT启动
如图,点击免ROOT启动,会提示先修复 MaterKey 漏洞。

我们点击获取系统补丁。会下载一个安装包并且进入安装模式。


使用过 Android 手机的同学这时候应该会注意到什么。没错,这是更新。而不是重新安装。有同学就问了,我之前没有安装过一个叫做 “LBE Master Key漏洞补丁” 的东西啊,怎么会是更新呢?没错,这就是 LBE 利用 Master Key 漏洞 实现的更新系统应用。安装之后就会重启,重启之后就可以开启安全防御了。这时候什么卸载系统应用,权限管理等操作都可以实现。这些我们不关心。我们去看看“LBE Master Key漏洞补丁”这货到底是个什么。为什么安装了它就可以实现 免ROOT 模式。我们去系统设置,应用里面找到它。如图。


事实再一次证明我们是正确的。有一个卸载更新的按钮,这个时候应该一部分同学知道了。只有更新的系统应用才会有卸载更新,否则只有卸载。那我们来卸载更新来看看它到底替换了哪个应用。卸载之后露出了真身。如图


Icon 和 VersionName 都没换,只是加了自己的代码。换了 APP 的名字。

所以,LEB 的 免 ROOT 的实现原理就是,通过利用 Master Key 漏洞替换系统本身应用而实现加载自己的代码。这个时候自己的代码拥有最高权限。便可以实现卸载系统应用,权限管理等操作。

我们再说一下为什么 LBE 要替换 Settings Storage 这个应用。简单的说 Settings Storage 是一个 Android 内部程序,在 Android 开机时就会加载,这也是 LBE 要在开机时把自己的代码 HOOK 到系统上的必要条件。

那为什么 LBE 可以替换系统内部应用呢。其实就是利用了 Master Key 漏洞。在不修改 APP 签名的同时可以修改 APP 的代码。LBE 拿到 Settings Storage 这个 APP。反编译,修改代码,重新打包。就可轻易实现了。而关于 Master Key 漏洞,下面的 Android 的源码应该可以说明了。这里就不详解。

再说一下,这个漏洞真的很危险么?其实只要你做到不允许安装来自 Google Play 以外其他来源的应用。这个漏洞根本影响不到你的。实际上 Google 在 8 月已经向各大手机厂商提交了该漏洞的补丁,并且对 Google Play 上的应用做了关于该漏洞的扫描。而且 Google Play 不允许提交同系统包名一样的 APP。也就不会存在替换系统应用的现象。