Xcode调试所需要的临时空间非常大,而且不会自动删除,长年累月积累,会造成严重的空间浪费。我的硬盘就白白耗费了22G。缓存的位置:

/Users/<用户名>/Library/Developer/Xcode/DerivedData/

里面包含了大量的缓存文件,都是在编译调试时使用的。很多都是历史遗留的不再使用的文件。直接删除相应文件夹即可。

对于当前工程来说,删除以上文件夹相当于做了一次clean。

新版的OpenSSH客户端修改了指纹Hash方式,例如:

# ssh 192.168.10.229 -p 2222 -l root
The authenticity of host '[192.168.10.229]:2222 ([192.168.10.229]:2222)' can't be established.
ECDSA key fingerprint is SHA256:TosANrD9LxFcgw4i9u1dE837g2LnGabdNXXpjz7USKw.
Are you sure you want to continue connecting (yes/no)?

如果我们服务端不支持生成TosANrD9LxFcgw4i9u1dE837g2LnGabdNXXpjz7USKw这样的指纹,那么我们就无法做对比了(无法确认是否有中间人攻击)。一个妥协的方法,是让客户端以旧版md5方式产生证书的Hash,命令如下:

# ssh 192.168.10.229 -p 2222 -l root -o FingerprintHash=md5
The authenticity of host '[192.168.10.229]:2222 ([192.168.10.229]:2222)' can't be established.
ECDSA key fingerprint is MD5:dd:7d:0e:71:f0:2b:6a:87:89:d3:63:1c:2d:61:11:0c.
Are you sure you want to continue connecting (yes/no)?

这样就与服务端ssh-keygen -lf xxx.pub生成的指纹格式一样了。

本文转载自水景一页

CentOS 7 已经切换到 systemd,系统指令也有所变化。之前用于启动、重启、停止各种服务的 service 作为向后兼容的指令还能使用,但是将来可能会消失。同时,chkconfig 也改成了 systemctl 了。这里列举了一些常用的对应于 service 和 chkconfig 的新的 systemctl 指令。

在目前的 CentOS 7(或 RHEL 7)系统中,依然可以使用 service 指令。例如,

[root@localhost ~]# service network restart
Restarting network (via systemctl):                        [  OK  ]

[root@localhost ~]# service httpd restart
Redirecting to /bin/systemctl restart  httpd.service

[root@localhost ~]# service sshd restart
Redirecting to /bin/systemctl restart  sshd.service

但是系统会自动重定向该指令到新的指令 /bin/systemctl 来执行,并给出提示。

是时候切换到新的指令格式了,直接使用 systemctl 吧。这个指令的意思就是 system contrl。下面是一些常用的例子:

启动服务:

systemctl start httpd

停止服务:

systemctl stop httpd

重启服务(先停止,后启动):

systemctl restart httpd

重新加载(使用新的配置文件):

systemctl reload httpd

显示服务状态:

systemctl status httpd

与此同时,之前用于设定系统启动时自动运行某服务的指令 chkconfig 也改了,还是用 systemctl。

chkconfig service on

改成了,

systemctl enable httpd
chkconfig service off

改成了,

systemctl disable httpd

检查服务状态的

chkconfig service

改成了,

systemctl is-enabled httpd

列举出所有服务的指令,

chkconfig –list

改成了,

systemctl list-unit-files --type=service

以前能指定服务 runlevel 的 –levels 也没有了。慢慢适应吧。

问题描述

Sublime Text支持VIM模式,但是有个问题,就是Insert模式下,Esc键与自动完成冲突。当遇到自动完成窗口时,按下Esc键不是退出Insert模式,而是关闭自动完成窗口,这样非常不方便。

解决方法

原理参见文章。解决方法很简单,已经有人做好插件了。只需要用Package Control下载Vintage Escape插件即可。

这篇文章是去年为某公司的面试准备的,虽然最终没有被录用,但是在这过程中收获很多,总结出这篇文章与大家分享。对于逆向分析我纯属于爱好者水平,而且之前主要以Android smali为主,对Win32经验并不多,文章中大部分内容都是现学现卖,最终没有被录用的原因是还有一个重要的地方我没有分析出来。不过以我有限的经验,无法再继续,在此也希望有大神指点一二,不胜感激!!


360出的XP盾甲,为Windows XP实现了Vista以上版本才有的ASLR机制,这个机制会使绝大多数溢出类漏洞失效或难以利用。这也是为什么360这么自信的宣传360盾甲。下面是我对此机制实现过程的逆向分析,看看360用了什么黑科技搞定这件事情的。

什么是ASLR?

对溢出类漏洞的攻击,会用到许多系统共享库,在XP及之前的系统,这些共享库的内存地址是固定的。构造溢出代码时,可以很方便的调用这些共享库的API。例如:LoadLibrary函数在XP下地址是0x7C80AEEB,直接调用即可。当然还有其它的漏洞利用方式,但几乎都必须依靠固定的地址实现。ASLR全称是Address Space Layout Randomization(地址空间布局随机化)。它通过随机化共享库的加载地址,使以上攻击失效或难以利用。

ASLR的效果

这里我写了一小段程序ASLRTest,用来输出各个库的加载地址。输出结果如下:

未使用XP盾甲:

Ntdll的加载地址:7C920000
Kernel32的加载地址:7C800000
LoadLibrary函数的地址:7C80AEEB
MSVCR120.dll的加载地址:10000000
system函数的地址:100808C2
本程序customFunc函数的地址:00401000
按任意键继续。

使用XP盾甲后:

Ntdll的加载地址:77040000
Kernel32的加载地址:76CD0000
LoadLibrary函数的地址:76CDAEEB
MSVCR120.dll的加载地址:6BEB0000
system函数的地址:6BF308C2
本程序customFunc函数的地址:00401000
按任意键继续。

继续阅读

Sysmon安装后会生成如下两个文件:

C:\Windows\Sysmon.exe
C:\Windows\SysmonDrv.sys

显然Sysmon使用了驱动级监控,需要IDA+WinDBG+VMware组合,搭建双机驱动调试环境才能对SysmonDrv.sys进行有效的调试。

通过IDA+WinDBG的静态分析和动态跟踪,发现其使用PsSetCreateProcessNotifyRoutine函数,来监控进程的创建。关键代码如下:

.text:FFFFF880018AEA99 ; ---------------------------------------------------------------------------
.text:FFFFF880018AEA99
.text:FFFFF880018AEA99 loc_FFFFF880018AEA99:                   ; CODE XREF: sub_FFFFF880018AE730+349
.text:FFFFF880018AEA99 mov     rcx, cs:qword_FFFFF880018B4498
.text:FFFFF880018AEAA0 call    cs:FltStartFiltering
.text:FFFFF880018AEAA6 call    sub_FFFFF880018ADD00
.text:FFFFF880018AEAAB lea     rcx, sub_FFFFF880018ADBA0
.text:FFFFF880018AEAB2 call    cs:PsSetCreateThreadNotifyRoutine
.text:FFFFF880018AEAB8 lea     rcx, sub_FFFFF880018ADC40
.text:FFFFF880018AEABF xor     edx, edx
.text:FFFFF880018AEAC1 call    cs:PsSetCreateProcessNotifyRoutine
.text:FFFFF880018AEAC7 xor     eax, eax

回调函数地址为:sub_FFFFF880018ADC40(动态地址)。每当有新进程创建时,都会回调这个函数。回调时,寄存器RCX保存父进程PID,RDX保存子进程PID。

PsSetCreateProcessNotifyRoutine函数定义如下:

NTSTATUS PsSetCreateProcessNotifyRoutine(
  _In_  PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
  _In_  BOOLEAN Remove
);

回调函数定义如下:

VOID
(*PCREATE_PROCESS_NOTIFY_ROUTINE) (
    IN HANDLE  ParentId,
    IN HANDLE  ProcessId,
    IN BOOLEAN  Create
    );

对于文件创建时间修改的监控,则是通过Minifilter驱动实现的。大体原理是,注册一个文件过滤器,监控对文件的操作,一旦发现有修改文件日期的行为,就记录日志。过程如下:

注册过滤器:

.text:FFFFF8800164FA5E                 mov     rcx, rdi
.text:FFFFF8800164FA61                 mov     cs:qword_FFFFF880016554A8, rax
.text:FFFFF8800164FA68                 mov     cs:qword_FFFFF880016554A0, rax
.text:FFFFF8800164FA6F                 call    cs:FltRegisterFilter

启动过滤器:

.text:FFFFF8800164FA99 ; ---------------------------------------------------------------------------
.text:FFFFF8800164FA99
.text:FFFFF8800164FA99 loc_FFFFF8800164FA99:                   ; CODE XREF: sub_FFFFF8800164F730+349
.text:FFFFF8800164FA99                 mov     rcx, cs:qword_FFFFF88001655498
.text:FFFFF8800164FAA0                 call    cs:FltStartFiltering

回调函数:

.text:FFFFF8800164DBD9 loc_FFFFF8800164DBD9:                   ; CODE XREF: sub_FFFFF8800164DB90+39
.text:FFFFF8800164DBD9                 cmp     [rdi+50h], bl
.text:FFFFF8800164DBDC                 jnz     short loc_FFFFF8800164DC21
.text:FFFFF8800164DBDE                 cmp     dword ptr [rax+20h], 4
.text:FFFFF8800164DBE2                 jnz     short loc_FFFFF8800164DC21
.text:FFFFF8800164DBE4                 cmp     dword ptr [rax+18h], 28h ; '('
.text:FFFFF8800164DBE8                 jb      short loc_FFFFF8800164DC21
.text:FFFFF8800164DBEA                 mov     rdi, [rax+38h]
.text:FFFFF8800164DBEE                 test    rdi, rdi
.text:FFFFF8800164DBF1                 jz      short loc_FFFFF8800164DC21
.text:FFFFF8800164DBF3                 mov     rax, [rdi]
.text:FFFFF8800164DBF6                 add     rax, 2
.text:FFFFF8800164DBFA                 cmp     rax, 2
.text:FFFFF8800164DBFE                 jbe     short loc_FFFFF8800164DC21
.text:FFFFF8800164DC00                 mov     rcx, rsi
.text:FFFFF8800164DC03                 call    sub_FFFFF8800164D6B0 ; 这里调用文件信息查询函数FltQueryInformationFile,查询是否符合条件。符合条件返回1,可以人工修改结果使其效果相反。
.text:FFFFF8800164DC08                 test    al, al
.text:FFFFF8800164DC0A                 jz      short loc_FFFFF8800164DC21
.text:FFFFF8800164DC0C                 mov     rdx, [rdi]
.text:FFFFF8800164DC0F                 mov     rcx, rsi
.text:FFFFF8800164DC12                 call    sub_FFFFF8800164D720 ; 如果确实是需要记录的操作,那么调用此子函数,获取文件信息以及调用者的PID。
.text:FFFFF8800164DC17                 test    rax, rax
.text:FFFFF8800164DC1A                 jz      short loc_FFFFF8800164DC21
.text:FFFFF8800164DC1C                 mov     [r14], rax
.text:FFFFF8800164DC1F                 xor     ebx, ebx

每次回调时通过FltQueryInformationFile函数查询文件的信息,来判断是否修改。

NTSTATUS FltQueryInformationFile(
  _In_       PFLT_INSTANCE Instance,
  _In_       PFILE_OBJECT FileObject,
  _Out_      PVOID FileInformation,
  _In_       ULONG Length,
  _In_       FILE_INFORMATION_CLASS FileInformationClass,
  _Out_opt_  PULONG LengthReturned
);

FILE_INFORMATION_CLASS结构体是多种类型的,FILE_NETWORK_OPEN_INFORMATION类型保存了文件的各个时间属性。

通过OD跟踪,很容易发现TCPView使用了Windows的两个关键的API来实现这个功能。两个API的定义:

DWORD GetExtendedTcpTable(
  _Out_    PVOID pTcpTable,
  _Inout_  PDWORD pdwSize,
  _In_     BOOL bOrder,
  _In_     ULONG ulAf,
  _In_     TCP_TABLE_CLASS TableClass,
  _In_     ULONG Reserved
);

DWORD GetExtendedUdpTable(
  _Out_    PVOID pUdpTable,
  _Inout_  PDWORD pdwSize,
  _In_     BOOL bOrder,
  _In_     ULONG ulAf,
  _In_     UDP_TABLE_CLASS TableClass,
  _In_     ULONG Reserved
);

使用这两个函数,可以获取所有的TCP/UDP连接的列表,保存在以下两个结构体中(IPv6类似,这里不列出了):

typedef struct {
  DWORD                dwNumEntries;
  MIB_TCPROW_OWNER_PID table[ANY_SIZE];
} MIB_TCPTABLE_OWNER_PID, *PMIB_TCPTABLE_OWNER_PID;

typedef struct _MIB_UDPTABLE_OWNER_PID {
  DWORD                dwNumEntries;
  MIB_UDPROW_OWNER_PID table[ANY_SIZE];
} MIB_UDPTABLE_OWNER_PID, *PMIB_UDPTABLE_OWNER_PID;

以上结构体中都有一个数组,而进程与端口号的关联信息,都保存在数组中每一个MIB_TCPROW_OWNER_PIDMIB_UDPROW_OWNER_PID结构体中。他们的定义如下:

typedef struct _MIB_TCPROW_OWNER_PID {
  DWORD dwState;
  DWORD dwLocalAddr;
  DWORD dwLocalPort;
  DWORD dwRemoteAddr;
  DWORD dwRemotePort;
  DWORD dwOwningPid;
} MIB_TCPROW_OWNER_PID, *PMIB_TCPROW_OWNER_PID;

typedef struct _MIB_UDPROW_OWNER_PID {
  DWORD dwLocalAddr;
  DWORD dwLocalPort;
  DWORD dwOwningPid;
} MIB_UDPROW_OWNER_PID, *PMIB_UDPROW_OWNER_PID;

结构体中的dwOwningPid就是PID信息。

TCPView程序中使用这两个函数的关键地方:

0040D3B5   .  83C1 07       add ecx,0x7
0040D3B8   .  51            push ecx
0040D3B9   .  6A 02         push 0x2
0040D3BB   .  55            push ebp
0040D3BC   .  52            push edx
0040D3BD   .  55            push ebp
0040D3BE   .  FF15 3C6B4400 call dword ptr ds:[0x446B3C]             ;  IPHLPAPI.GetExtendedTcpTable
0040D3C4   .  83F8 7A       cmp eax,0x7A
0040D3C7   .  75 47         jnz XTcpview.0040D410
0040D3C9   .  8DA424 000000>lea esp,dword ptr ss:[esp]
0040D3D0   >  3BFD          cmp edi,ebp
0040D3D2   .  74 09         je XTcpview.0040D3DD
0040D3D4   .  57            push edi
0040D3D5   .  E8 EB540000   call Tcpview.004128C5
0040D3DA   .  83C4 04       add esp,0x4
0040D3DD   >  8B4424 14     mov eax,dword ptr ss:[esp+0x14]
0040D3E1   .  50            push eax
0040D3E2   .  E8 AC500000   call Tcpview.00412493
0040D3E7   .  83C4 04       add esp,0x4
0040D3EA   .  33C9          xor ecx,ecx
0040D3EC   .  380D 156E4400 cmp byte ptr ds:[0x446E15],cl
0040D3F2   .  55            push ebp
0040D3F3   .  0F95C1        setne cl
0040D3F6   .  8D5424 18     lea edx,dword ptr ss:[esp+0x18]
0040D3FA   .  8BF8          mov edi,eax
0040D3FC   .  83C1 07       add ecx,0x7
0040D3FF   .  51            push ecx
0040D400   .  6A 02         push 0x2
0040D402   .  55            push ebp
0040D403   .  52            push edx
0040D404   .  57            push edi
0040D405   .  FF15 3C6B4400 call dword ptr ds:[0x446B3C]             ;  IPHLPAPI.GetExtendedTcpTable
0040D40B   .  83F8 7A       cmp eax,0x7A
0040D40E   .^ 74 C0         je XTcpview.0040D3D0

0040D494   .  57            push edi
0040D495   .  6A 01         push 0x1
0040D497   .  6A 02         push 0x2
0040D499   .  57            push edi
0040D49A   .  8D5424 24     lea edx,dword ptr ss:[esp+0x24]
0040D49E   .  52            push edx
0040D49F   .  57            push edi
0040D4A0   .  C74424 2C 000>mov dword ptr ss:[esp+0x2C],0x0
0040D4A8   .  FF15 286E4400 call dword ptr ds:[0x446E28]             ;  IPHLPAPI.GetExtendedUdpTable
0040D4AE   .  83F8 7A       cmp eax,0x7A
0040D4B1   .  75 35         jnz XTcpview.0040D4E8
0040D4B3   >  85FF          test edi,edi
0040D4B5   .  74 09         je XTcpview.0040D4C0
0040D4B7   .  57            push edi
0040D4B8   .  E8 08540000   call Tcpview.004128C5
0040D4BD   .  83C4 04       add esp,0x4
0040D4C0   >  8B4424 14     mov eax,dword ptr ss:[esp+0x14]
0040D4C4   .  50            push eax
0040D4C5   .  E8 C94F0000   call Tcpview.00412493
0040D4CA   .  83C4 04       add esp,0x4
0040D4CD   .  6A 00         push 0x0
0040D4CF   .  6A 01         push 0x1
0040D4D1   .  6A 02         push 0x2
0040D4D3   .  6A 00         push 0x0
0040D4D5   .  8D4C24 24     lea ecx,dword ptr ss:[esp+0x24]
0040D4D9   .  8BF8          mov edi,eax
0040D4DB   .  51            push ecx
0040D4DC   .  57            push edi
0040D4DD   .  FF15 286E4400 call dword ptr ds:[0x446E28]             ;  IPHLPAPI.GetExtendedUdpTable
0040D4E3   .  83F8 7A       cmp eax,0x7A
0040D4E6   .^ 74 CB         je XTcpview.0040D4B3
0040D4E8   >  85C0          test eax,eax

默认git会记录文件的权限信息,如果文件的权限信息被修改,那么git也作为一个差异保存。但是我们有时候是不需要这方面的差异的(例如在Windows下使用Cygwin),这时需要关闭文件权限的检查。

git中可以加入忽略文件权限的配置,具体如下:

$ git config core.filemode false
$ git config --list

还有一个小问题,在设置这个属性之前权限就混乱的话,是无法自动修复的。这时候,如果仅仅是权限混乱的话,直接git reset --hard恢复吧,git会将项目完全恢复到最近一次提交,包括权限。

  1. 测试磁盘写能力
    time dd if=/dev/zero of=/test.tmp bs=64k count=16k
    

    因为/dev/zero是一个伪设备,它只产生空字符流,对它不会产生IO,所以,IO都会集中在of文件中,of文件只用于写,所以这个命令相当于测试磁盘的写能力。

    但是这个命令得到的数据不准确,因为命令结束的时候数据还没有真正写到磁盘上去。

    time dd if=/dev/zero of=/test.tmp bs=64k count=16k conv=fsync
    

    这个还算准确,数据已经写入磁盘。

    time dd if=/dev/zero of=/test.tmp bs=64k count=4k oflag=dsync
    

    这个可以当成是模拟数据库插入操作,所以很慢。

  2. 测试磁盘读能力
    time dd if=/dev/sda1 of=/dev/null bs=8k
    

    因为/dev/sda1是一个物理分区,对它的读取会产生IO,/dev/null是伪设备,相当于黑洞,of到该设备不会产生IO,所以,这个命令的IO只发生在/dev/sda1上,也相当于测试磁盘的读能力。

  3. 测试同时读写能力
    time dd if=/dev/sda1 of=/test.tmp bs=8k
    

    这个命令下,一个是物理分区,一个是实际的文件,对它们的读写都会产生IO(对/dev/sda1是读,对/test.tmp是写),假设他们都在一个磁盘中,这个命令就相当于测试磁盘的同时读写能力。

Java中已经有for eachfor index的方法来遍历集合,为何还要存在迭代器这种东西呢?其实迭代器有其它方式无法实现的功能,那就是遍历/修改的模式。两种for循环在遍历集合的时候非常方便,但是在遍历过程中,如果存在修改集合的需求,就会出现效率问题了。

这里以一个经典的例子作为解释。情景是,有一个LinkedList,在遍历过程中需要删除当前遍历到的元素。这时无论是使用remote(int location)还是remote(Object object)方法,都存在效率问题。因为根据链表的特性,这两个方法都需要从头再遍历一遍。这样,相当于两个循环嵌套,导致时间复杂度变为(O^2)。用迭代器就能很好的解决这个问题。以下是一个用迭代器的示例代码:

mBokehPoints = new LinkedList<BokehPoint>();
for (Iterator<BokehPoint> iter = mBokehPoints.iterator(); iter.hasNext();) {
    BokehPoint e = iter.next();
    if (e.updatePoint()) {
        ......
    } else {
        iter.remove();
    }
}

以上代码在遍历时使用了迭代器的remove方法来删除特定的元素,这个方法不需要重新遍历链表,而是直接将当前位置的元素删除。

当然,迭代器还有其它的意义,比如迭代器是集合遍历的基础方法,迭代器统一了遍历接口,集合中许多功能的实现都与迭代器有关(remove方法底层就是迭代器实现)。

注意:网上有好多在链表遍历时使用remove方法的代码,这是很低效的做法,需要用迭代器修正。