Browsed by
月份:2016年2月

将HHKB的左Alt改为Control

将HHKB的左Alt改为Control

HHKB 到手, 经过简单的通过跳线开关修改键位配置之后, 发现 Control的位置很是反! 人! 类! (没错我就是说给Emacs党听的233)  作为一个长期用terminator Control是很常用的按键, 因此决定对键盘按键映射进行修改

首先 我先把 左Alt->Fn的这个跳线开关关闭了, 不然 keyscan的时候读不出来(Fn没有键盘码不知道为什么, 也许是因为我在X 下键盘码被转义了) 然后 , 运行 xev 这个程序 , xev可以给出按键对应的键盘码, 查看了一下HHKB左Alt的键盘码, 得到如下信息

使用 xmodmap对键位映射进行修改 先使用了这个指令 :

xmodmap -e “keycode 102 = Control_L” 再次查看 xev 发现果然修改了, 信息变为了这样

不过当我press 修改后的Alt_L之后, 发现和我按Control的结果是不一样的 , 没法用Control C 没法 Control Tab , 说明修改keysym是不够的 因而转而修改 key modifier, 首先查看了已有的modifiers

xmodmap -pm 发现 Control_L 这个按键在 control这个modifier 组里,  因此将 Muhenkan(keycode 102, keysym 0xff22) 加入到 control 这个modifier组里

xmodmap -e “add control = 0xff22”

再次尝试, 这次成功了

为了保证以后使用不用每次输入这个指令 , 在HOME下新建.Xmodmap文件,将expression填进去

add control = 0xff22

再去配置一下 ~/.xinitrc 设置 xmodmap开启Xserver就会启动 即可~

[Android 开发学习] 认识App

[Android 开发学习] 认识App

应K酱邀请, 做一款桌面宠物App, 不过自己对Android开发一无所知, 于是就从0学起, 下文是从Android SDK Document 中摘录的内容, 供参考学习

应用程序(app)基础

每个应用程序都运行在独立的沙盒里, 拥有一个系统分配的用户ID, 只有其有权限访问的资源才能够访问 应用程序之间共享资源的方式有, 1. 分配同样的用户ID给两个应用程序, 这样他们就可以获得同样的权限以及资源, 通常这种情况下, app会运行在同一个VM中, 甚至同一个进程上, 这种共享方式要求这两个App拥有同样的证书 2.通过向系统请求权限,如阅读联系人记录, 读取短信信息等 这些特权都需要用户在安装的时候进行设置(之后也可以修改)

App的成分结构

Activitiy

每个Activity都是一个用户界面, (类似窗体), 一个App可以有多个Activity, 其他App可以调用该App下的某个Activity, 比如, 一个邮件客户端, 拥有一个邮件列表Activity,一个邮件发送Activity,  另一个相机App支持以email形式分享照片, 因此相机可以启动邮件客户端的邮件发送Activity

Services

Service是在后台运行的进程, 不提供用户界面, 后台运行, Activity可以启动一个Service 或者绑定到某个service上

Content Provider

Content Provider 就是一个管理shared data的接口(?) , 一个App可以把数据存在数据库, 网上, 本地存储 , 等存储介质中,  其他App可以通过请求Content Provider提供数据给他们,

Broadcast Receivers

接收器, 用于接收系统内广播的消息(如用户锁屏, 下载完成之类的..) App也可以自己发出Broadcast,  Broadcast Receivers 不会显示UI, 不过他们可以显示一个Notification(在Status bar上) 更通常的, Broadcast Receiver只是一个Gateway, 可能某个事件被他接收到之后, 他会去启动一个Service, 或者Activity .它只做很少的事情

 

 

Calling Conventions 调用惯例

Calling Conventions 调用惯例

摘自维基, 暂时先搬运, 以后会加入自己的理解(又挖坑了 QWQ)

调用惯例涉及以下几点:

1. 函数参数的空间分配顺序

2. 这些参数存储在什么地方(是全部放在栈上,还是部分放在栈上,部分放在寄存器里,还是全部放在寄存器里)

3.被调用的函数需要保留哪些寄存器给调用他的函数

4.调用函数的时候, 保护现场, 恢复现场的顺序.

 __cdecl:
1> 参数按从右到左的顺序传递,放于栈中
2> 栈的清空由主调函数完成

 __stdcall:
    1> 参数按从右到左的顺序传递,放于栈中
2> 栈的清空由被调函数完成

 __fastcall:
1> 前两个参数要求不超过32bits,分别放入ECX和EDX,其余参数按从右到左的顺序传递,放于栈中
2> 参数由被调函数弹出栈

Thiscall,仅用于C++中类的成员函数:
1> 参数按从右到左的顺序传递,放于栈中。this放于ECX中
2> 栈的清空有被调函数完成

下面通过对cdecl 和 stdcall Calling convention 的区别的研究, 学习calling convention的相关知识

cdecl 是 C语言默认的调用惯例 , 也就是说, 如果你什么不加, default为cdecl ,这个调用惯例 , 要求caller清理堆栈, callee不用清理堆栈 , 用cdecl可以实现可变参数的函数, 另一种方式 stdcall, 是由 callee清理堆栈 , caller不负责堆栈的清理 ,下面是两个不同的调用的C代码及汇编   (注意, 在gcc中 想指定Calling Convention 需要用这样的形式 , 以 stdcall为例: __attribute__((__stdcall__)) , 另外注意, 想要看到Calling Convention的效果要将代码编译为 32位的程序而不是64位 , 提供一个编译指令  gcc -m32 -g -O0 xxx.c -o xxx.out 

call.h

stdcall.c

stdcall.s(part)

这里

显示出来了, 是由 add函数清理的堆栈 : ret $0x8 表明了是callee (即 add函数) 清理了堆栈,  在主函数没有清理堆栈 ,

另外一段代码, 只把这个代码里的STDCALL换成CDECL, 然后得到的汇编代码如下:

这里

是在主函数对堆栈进行清理的

那么现在就可以猜测,如果我在调用一个函数的时候使用不同的Calling Convention会导致程序异常么? 通过cdecl 和stdcall的对堆栈的处理, 做出如下猜想:

如果caller 用STDCALL的形式调用 callee 声明为CDECL的形式, 那么由于STDCALL将清理堆栈的任务交给callee, CDECL将清理堆栈的任务交给caller, 那么就导致 caller 和 callee谁都没有清理堆栈, 反过来 ,如果caller是CDECL callee 是 STDCALL 那么这样, 就导致 caller 和 callee 都对堆栈进行了清理, 也就是堆栈被重复释放了两次 下面通过代码来验证这个猜想

* PS: 这里如何实现 Convention的混合使用,有一定技巧,我采用的方式是函数指针, 先定义一个函数A, 用ConventionA ,再定义一个函数指针B指向A, 不过B的Convention和A的不同 代码如下:

sample: caller is CDECL callee is STDCALL

可以看出, 我们定义了函数add 并且声明了函数指针 fun指向add, 然后在main里调用了fun, 为了保证结果的直观性, 这里使用了内联汇编,  将esp ebp在函数调用前后的值都保存下来了, 作为对比 内联汇编的格式可以在这里找到 https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html 然后, 运行程序, 观察结果, 因为每次程序初始化的时候esp, ebp指向的地址有所不同, 但是调用前后, esp位置应该是相同的, 运行程序得到的一个可能结果如下

注意看, 这里nowesp 和 preesp 差了8 , 这个意味什么稍后再说, 我们再将CDECL 和 STDCALL的位置互换 , 重新编译运行 得到的结果如下:

我们知道 在IA32程序中, 栈的增长是向低地址增长的, 也就是说, 压栈会导致esp减小, 那么 我们来解释一下之前的现象, 在第一次试验中, esp最终增加了 8 也就意味着, esp被多清理了一次, caller清理好堆栈之后, callee又清理了一次, 导致esp最后”错位”了8个字节, 而第二次试验, esp最后减少了8, 这就是二者都没有清理堆栈的后果, 栈内还存着传过去的参数的信息, 这样两周情况, 都可能导致程序崩溃, 也就是ABI不兼容导致的程序崩溃

给add函数增加一个参数int c 然后修改下面的函数指针和函数调用之后, 再次运行代码, 发现esp最后差12, 也进一步说明了, 这个esp的异常值是因为没有清理堆栈内的参数或者二次清理堆栈内的参数表导致的

另外 如果将程序里两个Calling Convention替换成一样的, 不论是CDECL还是都是STDCALL, 那么 esp在调用前后都是保持不变的,

不过之前写的代码都没有引起程序崩溃, 下面这段代码做到了使程序崩溃, 然后之要将 Calling Convention改为一样的, 就避免掉了崩溃 , 这段代码为什么会让它崩溃的原因还在研究, 个人猜测是因为: 循环中的这个计数变量被存在了栈内, 因此由于每次调用函数栈都会错位, 最后这个i就出问题了

 

 

[wine] 将WindowsPath转为UnixPath的解决方案

[wine] 将WindowsPath转为UnixPath的解决方案

参考这个代码

wine-devel maling list

要在wine下实现对wpcap的兼容, 使用了wrapper的手段来进行, 即不自己实现wpcap的相应函数, 通过调用Linux下的pcap相应的函数, 达到同样的效果. 这个函数的作用是将监听到的数据dump到fname指定的文件里, 因Linux下的文件路径和Windows的不同, 想要调用LInux原生的pcap_dump_open之前需要进行路径的转换,因此尝试进行修改, 变成这个样子:

然后很干脆的跪了

Convert to Widechar 就出问题了 , 经过查看MSDN 的MultiByteToWideChar得到了相应的信息:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072(v=vs.85).aspx 参考MSDN

cchWideChar [in]

Size, in characters, of the buffer indicated by lpWideCharStr. If this value is 0, the function returns the required buffer size, in characters, including any terminating null character, and makes no use of the lpWideCharStr buffer.

因为我的cchWideChar = 0 所以转换后的结果没有存到fname_W里, 因而转换失败

 

在IRC上请教了wine开发者之后, 选用了RtlInitAnsiString + RtlAnsiStringToUnicodeString + RtlDosPathNameToNtPathName_U + wine_nt_to_unix_file_name 的方法, 注意 一定要有 RtlDosPathNameToNtPathName_U 这个函数, 将 由前两个函数转换得到的DosPath转换为NtPath, 不然在wine_nt_to_unix_file_name的时候会出错(STATUS_OBJECT_NAME_INVALID) 不合法的NtPath, 然后经过修改的代码如下:

这个代码还有内存泄露和没有错误检查的问题, 需要继续修改,不过已经可以将winpath转换为unixpath了

空间红包谜题解法(Linux + base64 + HTTP Header + 摩尔斯电码)

空间红包谜题解法(Linux + base64 + HTTP Header + 摩尔斯电码)

题目

解密红包, 支付宝中文口令红包

(后来被人说二维码扫完还得用电脑重输一遍网址好麻烦 = = 于是我就把二维码对应的网址给出来了 : http://1.justquiz.sinaapp.com/voidmengmengda) —- 这就是完整的题干了, 谜题总共有三关, 个人认为难度是递增的, 下面放出每一关的解法

解法

* 第一关

首先看第一关的内容, 网页本身查看源码并没有什么用处, 不过注意到标题, “请用桌面浏览器打开哦~” 桌面浏览器(即Chrome Firefox) 和一般的移动端浏览器的区别就是, 桌面浏览器支持开发者视图, 可以看到更多详细信息, 除了看到源码, 我们还可以看到cookie session storage等东西, 也包括请求的header, 而这一关的线索就藏在了header里, 在服务器Response你的Request的时候, 会在header里带上下一关的线索,  之后我在空间里也对第一关进行了提示, 有十多人在提示之后到达了第二关QAQ 比我预期的少了很多 附上第一关解决的截图(点击可查看大图) 图中的 HintURL 就是第二关的线索

 

* 第二关

( 列出服务器网站目录) 进入到第二关, 你会发现看到一个在线编译器, 以及这样一段提示想信息:

Happy New Year~! Congrats! You have solve the first Challenge! See what you can find here
Remember : This is a BUGGY online Compiler
This is a BUGGY online Compiler 表示这个在线编译器是有bug的, 具体是什么bug就需要大家自己去找了, 这一关我没有再给提示, 大家稍微尝试之后就会发现, 这个online Compiler没有禁止系统指令的执行, (虽然用户权限是正确的, 无法删除root 的文件, 但是还是有很多事情可以做的)  因而编写下面代码到在线编译器里 , (我选用C语言做示例)

执行之后 ,会显示如下信息 :

稍微留心一下, 就会发现, 你列出的目录, 就是你当前访问的网站所在的目录, 同一级 ,再仔细看一眼列表 ,找到提示文件 thisIStheHintYouNeed.html 通过浏览器访问这个文件 , 得到下一关的提示信息, 本关解决. 附上本关解决之后的截图(点击查看大图)

 

* 第三关

这是本谜题的最后一关了, 也是我制作的时候花时间最多的一关(毕竟第一次用CoolEdit 以前从来没玩过QAQ) 通过第二关的最后提示, 得到一个网址 : 在浏览器里访问改网址 得到类似下面的东西(仅截取部分做展示)

看到这种形式的文件, 第一反应就是base64编码, 尝试用在线解码器进行解码 , 结果发现解出乱码了 , 推测这可能是一个二进制文件, 于是用Linux下自带的解码工具 (Windows下也许也有,不过我不清楚00.00) 将文件解码之后, 输出到另一个文件, 注意不要带后缀名, 带后缀名会影响linux对文件类型的推测, 一会儿要进行文件类型的推测 执行下面指令得到解码后的文件 :

然后推测文件类型 , 通过hexdump xxd 等工具并没有看出文件是什么类型的 = = (也许是我自己能力不够) 因此使用linux下的file指令推测文件类型

通过这个可以看出, 这应该是一个媒体文件 , 因此用播放器对其进行播放 , (linux 下有工具 playsound 或者修改后缀名进行播放) 听到电报音, 长短结合,  想到可能是摩尔斯电码, 然后根据摩尔斯电码表对应下来 密码为  100081  转成中文 一零零八一, 输入进口令, 然而并不对 , 这是这一关的最后一个陷阱, 发现不对之后, 回去看一下第二关的提示URL :  最后面 drowssap.txt 看起来是不是很眼熟,  他就是单词password的逆转, 这是重要的提示信息,因此就说明要对摩尔斯电码进行逆转, 那么到底是把所有的数字颠倒顺序, 还是指把点(.) 和划(-) 的表示颠倒? 尝试之后发现 , 逆转得到的密码为  180001  而将点划表示颠倒之后得到的密码为  655536  作为一个程序员, 这两个选择哪个就不难决定了吧~  到此整个谜题全部解开了, 在支付宝页面输入正确的密码对应的中文, 就会拿到红包啦~    

 

 

后记 : 最后也没有人拿到那个红包QAQ,  不过还是有很多人很接近答案了~ 解密红包的乐趣在于解密而不是红包~ 我是玩的很愉快, 大家也玩的很愉快就好~

 

附上解密后的音频文件:

hint

以及摩尔斯电码对照表

数字

字符 电码符号 字符 电码符号 字符 电码符号 字符 电码符号
0 ━ ━ ━ ━ ━ 1 .━ ━ ━ ━ 2 ..━ ━ ━ 3 ...━ ━
4 ....━ 5 ..... 6 ━ .... 7 ━ ━ ...
8 ━ ━ ━ .. 9 ━ ━ ━ ━ .