编程

园区888路查询工具

手机java版园区888路公交汽车查询工具。
目前支持j2me的版本:CLDC 1.1 MIDP 2.0

做j2me经验不是很足,有bug或者其他的建议请留言或者联系我。

已知在我的N70上能很好的运行。
如果你需要支持你的手机,请留言或者跟我联系。

下载地址:

破解碰到的两两异或问题

昨晚,不想睡觉,就在电脑上随便逛逛。

以前在看雪论坛(很好的论坛)下载过一堆玩意儿,有教程也有工具。那个时候,不知道自己是太浮躁了还是怎么的,没怎么用心研究。

昨晚就认认真真研究了直到早上4点,事实上我这几天都是这么晚睡的。

我开始看一点破解教程,然后试着破解教程里的几个样例程序。前面几个很简单,后面居然碰到一个让我没法下手的,我就去睡了。

今天早上起来继续,发现,原来这个玩意儿挺简单的。

首先,破解之后发现,程序是需要输入一个8位的序列号,这个序列号跟0×32(50)异或后得到一个新的序列号,然后这个新的8位的序列号两两异或得到4位的,4位的两两异或得到2位数,然后再异或得到一个数放在al寄存器里。暂时把这个数命名为al吧。然后将al与那个新的8位序列号异或之后得到一个最终8位序列号,最后将这个最终的结果与程序里存储的8位标准序列号相比较,相同则破解成功,否则序列号不正确。

当然,破解不是我的目的,写个算法给算出来才过瘾。

以python为准的。首先定义一个8位列表,s[0]…s[7] 存储输入的序列号。然后定义一个程序里原来的 8位标准序列号,o[0]…o[7],然后:
s[0] s[1] s[2] s[3] s[4] s[5] s[6] s[7] ^0×32 得到
n[0] n[1] n[2] n[3] n[4] n[5] n[6] n[7] 两两异或得到(第一个和第二异或,第三个和第四个异或,类推)
mid1[0] mid1[1] mid1[2] mid1[3] 再两两异或得到
mid2[0] mid2[1] 再两两异或得到
al 然后 将al 与 n[0]..n[7] 8个异或就得到最终的序列号。
当然这8个要跟 程序里定义好的8个o[0]…o[7]相同,这样就算序列号正确了。
这样看来,就是根据程序里的8个标准的序列号反推就能得到输入的序列号了。那怎么反推呢?
这个问题让我纠结了好久,最后,还是找到了规律。规律最后再说。首先给出自己写的算法,python版的。

1
2
3
4
5
6
7
8
9
10
11
12
# -*- coding:utf-8 -*-
#反汇编时得到的标准序列号
o=[0x71,0x18,0x59,0x1b,0x79,0x42,0x45,0x4c]
#求al,过程很有趣
al=0
for i in o:
	al^=i
#初始化输入所需的序列号,并求之
s=[0]*8
for i in range(8):
	s[i]=al^o[i]^0x32
	print chr(s[i])

接下来是C语言版的程序,来自看雪论坛,源地址。

虽然我的得出的结论与此无关,但是还是给了我灵感的。

首先楼主给了一个他找来的代码,他说不懂其中的原理。很囧,其实看他接下来的程序,如果他分析一下就知道了,不过他没有。

首先是他找来的代码。注意,虽然代码不同,但是,这篇文章里所有的代码都是一个原理,最后我会说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
void main()
{
 char middle_1[4];
 char middle_2[2];
 char b[8]={0x71,0x18,0x59,0x1B,0x79,0x42,0x45,0x4C} ;
 middle_1[0]=b[0]^b[1];
 middle_1[1]=b[2]^b[3];
 middle_1[2]=b[4]^b[5];
 middle_1[3]=b[6]^b[7];
 cout<<middle_1[0]<<middle_1[1]<<middle_1[2]<<middle_1[3]<<endl;
 middle_2[0]=middle_1[0]^middle_1[1];
 middle_2[1]=middle_1[2]^middle_1[3];
 char al=middle_2[0]^middle_2[1];
 cout<<al<<endl;
 for(int i=0;i<=8;i++)
 {
  b[i]=b[i]^al;
  b[i]=b[i]^0x32;
  cout<<b[i]<<' ';
 }
}

这个是正确的代码,但是还是没有我的那个简便。其实我那个python版的跟这个是一个原理。这个代码几乎和加密是反过来的,把程序里的标准8位序列两两异或,再运算,然后得到了al,最后通过al得到需要输入的8位序列;而我的是将标准8位序列全异或一遍,然后得到al。得到al了就能解决其他的问题了。

原理就在这里。这里面有个巧妙的地方,那就是异或的运算法则有交换律,分配律,和结合律。其中分配律和普通运算有点不同,要注意一下。但是只要交换律和结合律就能搞定了。

首先,假设输入的序列号是正确的。那么我们得到最终序列号就会跟程序里的标准的一样了。那就假设我们得到的最终序列号就是o[0]…o[7]。

那o[0]…o[7]这8个是怎么得到的呢,前面讲了是 al 与 n[0]…n[7]异或得到的。得到式子:
n[0]^al=o[0]
n[1]^al=o[1]

n[7]^al=o[7]

不难发现规律 o[0]^o[1] =(n[0] ^al)^(n[1]^al),根据结合律,o[0]^o[1] =n[0]^n[1]。哈哈,规律发现了,能得到 o[0]^o[1]^…o[7]=n[0]^n[1]…n[7]。

那怎么得到al呢,这就好办了,知道了结合律,那8个两两异或最后得到一个,还不是等价于8个相互异或得到一个么?

从这里可以看出,我的python版的程序和C语言版的是一个原理。

不过还有一种算法。这得追溯到看雪论坛的那位老大了,很有意思的人。他知道了异或的运算法则,但是走了弯路,居然在反推的时候,将8位输入序列和al设成9个未知数,而此时又有9个方程,那他就能推出这9个未知数了。虽然这个方法很笨,但是,我当时一筹莫展的时候可想不到这样的方法。所以,对于这位老大的研究精神我还是有点佩服的。贴出他最后的得出的程序,跟上面两个原理一样。再贴一下他的网址吧,http://bbs.pediy.com//showthread.php?t=66222&referrerid=207614那里有很有意思的推导过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <conio.h>
void main()
{
	int i;
	char c[8]={0x71,0x18,0x59,0x1B,0x79,0x42,0x45,0x4C};
	char a[8];
	char b=0;
	for(i=0;i<8;i++)
		b^=c[i];
	for(i=0;i<8;i++)
		{
			a[i]=c[i]^b^0x32;
		printf("%c",a[i]);
	}
	getch();
}

VC++ 6 程序转 VS2008 的错误

前一阵子在学校的博士生那里得来一个程序,是关于一个神经网络论文的实验的程序。由于那篇论文发的比较早,而现在我们现在的论文是基于那篇论文的,我们必须要重复他们的一些实验来保证那篇论文的数据的正确性。

程序是用的vc++ 6 的MFC 写的,其实最大的功能就是通过神经网络的一些算法对一些数据进行分析然后分类,也就是模式分类了。这些功能用MFC有点大材小用了,用命令行就可以了。当然这个程序也很有意思,通过MFC的消息映射来读取数据然后输出数据,但是消息映射用的是菜单上的按钮……

程序太老了,要用vs2008来跑,所以就要进行转换了。转换的问题不是很大,就是不明白MS哪来那么多的规矩,一套一套的,偏偏没事就更新换代。有关MFC的代码不是问题,但是有一点其它的问题。

首先是 include 问题,vs2008 对于 iostream 和 fstream 是不需要.h的后缀的,而且这些都在标准库中,因此需要用到std的命名空间,必须加上 using namespace std;(看情况而定了,有时候只加 std:: 更省事)

然后是 for 语句问题。现在的标准是 for 语句里面申明的变量在循环完之后就没有了,但是在vc6++里面是仍然存在的。

最后的问题就是比较让人纠结的了,执行出现类似如下错误:

Error  179  error C2248: std::basic_ios _Elem,_Traits::basic_ios : cannot access private member declared in class std::basic_ios _Elem,_Traits c:\program files\microsoft visual studio 8\vc\include\fstream 802

这个问题在MSDN上有人提出,但是没人给出答案。我查到了CSDN上,发现也有人出现类似错误,贴下他的出错的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <fstream>
int main(int argc, char* argv[])
{
    using namespace std;
 
    ( argc > 2
        ? ofstream(argv[2],ios::out|ios::binary)
        :cout
       ) <<
        ( argc >  1
        ? ifstream(argv[1],ios::in|ios::binary)
        :cin
        ).rdbuf() ;
 
    return 0;
}

CSDN上没人给出好的答案,后来他自己结贴了并给出了修改后的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <fstream>
int main(int argc, char* argv[])
{
    using namespace std;
    (*( argc > 2
        ? &ofstream(argv[2],ios::out|ios::binary)
        :&cout
        )) <<
 
        (*( argc >  1
        ? &ifstream(argv[1],ios::in|ios::binary)
        :&cin
        )).rdbuf() ;
    return 0;
}

从这里面什么也看不出来,但是总还是有一点端倪的。接下来在另一个论坛找到了相关问题的解决办法。有人回帖说这个问题可能是将一个fstream对象赋值给了另一个对象。里面也有人提到,是不是函数的形参不是通过引用传递的,这样也能出现这样的错误。

因此,我将所有的函数的形参都改过来了,最后发现,大功告成,除了一些警告之外,没有错误了。

自己做的一个邮件发送器

没什么好写的,留着以后自己慢慢自我欣赏了,其实我自己都是用客户端发邮件的,这个东西做出来一般自己都不用,丑不说,功能性还不强,不过,也算作一个纪念了。

嗯,有时间真的应该看看 软件工程 一系列的书,虽然自己目前还是个独行侠,但是,独行侠总归要有个侠的样子。
skydrive

上个图吧
send-mail-beta.jpg

今天

这算是日记吧,对于长期呆在电脑旁的我来说,日记发到博客最好了,存在电脑上反而不安全,我经常重装系统。 :mrgreen:

下午,逛天涯的时候碰到个人拿个程序叫嚣谁能几小时做出来……我用C语言实现了,得到了他给出的答案,但是觉得有点不足,因为还有个人也上传了代码,行数几乎是我的一半,而且没有我的那么繁冗。感觉自己要学的东西还有很多。

其实就是约瑟夫环算法,一般都用链表实现,但实际不必要,不知道为什么那么多人喜欢搞得那么麻烦。

代码就不上传了……

写完代码,嗯,就发现自己饿了,因为中午12点起床的,貌似没吃中饭,然后下午5点吃了晚饭。

去下面的超市买点东西吃,那家新开的,转了转,还是选择买饼干了。

正在挑的时候,突然听到超市放的音乐,孙燕姿的《我的爱》,感触颇多,好像回到了高二的时候。

高中时代高一和高三印象就只有几件事,高二给我留的印象蛮深刻,毕竟,初恋那个时候发生的,也说不清很谁开始的初恋,两个女孩,呵呵……那个时候,经常听歌,听周杰伦的新歌老歌,那时候 十一月的肖邦 刚出来。

还有孙燕姿的歌,都喜欢,其实听她的歌是我没办法,因为,不得不听,没得听了,貌似是谁要求我听来着,呵呵。

还记得《恋爱达人》那首歌,第一次是一个女孩给我听的,我还记得,还有《人鱼的眼泪》《彩虹天堂》,每次听到都容易想起那个时候的事情,周杰伦的《回到过去》,有时候真的有种回到过去的念头,但是,只是想想,真要回去还是没几个人想的……

晚上,写这篇文章的时候,老妈打电话来了,也不是什么重要的事情,说天气变凉了,要加衣服了,被单要自己洗,被子要弄出去晒,要我学习努力……不过这次没说不准我恋爱,她说就是我自己不愿意衣要找个女生帮我解决掉啊。因为我高中的时候说过这种话,呵呵,那时候老妈给我整理房间说我房间很乱,以后一个人过怎么办,我说找个贤惠的女友,让她帮我……现在想来不太现实了,现在哪来那种女人,如果真有,不管三七二十一,娶来做女朋友!

也应该把我当大人看了吧……她老人家想着我出国混个好工作。我说到我的计划,英国的硕士,中国的博士,她还是很赞同,看来,那个年代的人的认识真有点老套啊,不是出国就能赚钱,不是学历高就能赚钱的,但是,我好像没有办法说清楚,不然她要说我找借口玩的。

就写到这里啦,呵呵,把心里的东西写出来真舒服……特别是放到网上让别人都看得到,更……我有暴露癖?