修改 vs2010 编译器使之支持u8″字符串”的形式

一 3rd, 2011

vs有比较完善的unicode支持,从2005(或更早?)开始就支持源文件是utf-8,并且可以用中文做变量名函数名。(可以是可以,不推荐)

不过,也有一点很让人生气,就算源文件是utf-8编码的,编译时,他也会把utf-8转成主机的编码。所以,对于中文编码而言,如果源文件是

utf-8的并且有这样的内容,编译还是一样出问题:

const char * test = "®";
tt.cpp(10) : warning C4566: character represented by universal-character-name '\u00AE' cannot be represented in the current code page (936)

c++0x草案中有 u8″string literal” 形式的字符串,如果可以用这个,则问题解决,可惜的是,vs2010并不支持 u8-prefix string literal。当然,u和U也不支持。不过由于windows本身所说的unicode是utf-16 le,所以vc里L”string”就是u”string”。

如果才能让vc以持u8呢?写一个宏和字符串转化的类,在运行期转化是一个可行但比较折中的办法,这个办法最大的问题是依然不能在代码里写”®”这样的字串,因为编译期转成中文编码失败成?号,运行期转成utf-8还是问号。

当然,可以写 L”®”,这样这个u8类可以这样写:

string to_utf8(const wchar_t*);
#define U8(string)  to_utf8(string).c_str()

然后在用的地方写:

U8(L”®”);

这样基本能用,但带来了一些运行期消耗。并且L的字符串也比较大。当然宏本身还可以改改,使得不需要写L,而是在预处理后加入L,但会带来额外的限制(想想U8(“hello” “world”))。

能不能hack编译器加入u8的支持呢?经过一番研究,发现了点眉目。

首先,vc编译器编译的主要功能代码在c1xx.dll中。这个dll的x86版本位于 C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\c1xx.dll。惊喜的是微软提供了它的pdb,这样分析它的行为就大大简化了。

经过研究发现,vc基本上函展开,获取token生成语法树是一次过的。

在关键函数

4F4C9430 GetTokenFromCurrentChar

处,会有一个循环,从一个全局变量中读取解析到的内容,然后构造出一个token。我们要做的就是hack这个过程,如果当前token符合 u8″string”的形式,则处理一遍字符串,转成8进制的串表示方法。

经过一番苦战成功后,结果如下:

 
tt.cpp:
 
#define U8(str) u8##str
#define U16(str) L##str
 
int main()
{
 
U8("哈");
u8"哈";
return 0;
}
 
D:\temp>cl /E tt.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.
 
tt.cpp
#line 1 "tt.cpp"
int main()
{
 
"\345\223\210";
"\345\223\210";
return 0;
}

使用的办法是:

把原始的c1xx.dll重命名为c1xx_.dll,写了一个假的c1xx.dll,把导出函数的调用都重定位到c1xx_.dll。然后在GetTokenFromCurrentChar的循环开始处:

4F4C943E                                             8B3D 046C644F    MOV EDI,DWORD PTR DS:[Current_char]

写入一个跳转,跳转到自己的函数中检查是否需要替换字串。写完后变成:

4F4C943E                                             E8 4D7EB60E      CALL c1xx.asmReplCurCode
4F4C9443                                             90               NOP

这个被调用的函数是这样的:
__declspec(naked) void asmReplCurCode()
{
__asm
{
pushad;
call ReplCurCode;
popad;
mov edi, [ptrCurChar];
mov edi, [edi];
ret;
}
}
即用汇编做一个简单的包装,调用C++函数,然后完成被覆盖的代码要完成的事,然后ret回去。

ReplCurCode是这样的:

void ReplCurCode()
{
if (g_pred == 0)
{
g_pred = 1;
char ch = ** ptrCurChar;
//note: in creating/using precompiled header mode, don't insert this code since it had done before.
if (ch == '\r' || ch == '\n')
{
replace = *ptrCurChar;
const char * scode = "\r\n#define __bultin_u8 1\r\n1\r\n";
match = scode + strlen(scode)-3;
*ptrCurChar = scode;
return ;
}
}
 
if (*ptrCurChar == match)
{
*ptrCurChar = replace;
match = 0;
replace = 0;
}
 
const char * src = *ptrCurChar;
if (src[0] == '#' && src[1] == 'd')
{
int ff = 0;
}
 
string prefix;
while (isspace((unsigned char)(src[0])))
{
prefix += src[0];
++ src;
}
 
if (src[0] == 'u' &&  src[1] == '8' && src[2] == '"')
{
//so this is a U8 str.
string sb;
size_t sz = TextProcess::unescape(src+3, MAXLONG, sb);
if (src[sz+3] == '"')
{
string st = TextProcess::escape(sb.c_str(), sb.length());
string & codestr = getPool(prefix + st, src);
match   = codestr.c_str() + codestr.length();
replace = src+sz+4;
*ptrCurChar = codestr.c_str();
}
}
}

在首次处理的时候插入一个宏定义,这样代码中就可以知道编译器是不是修改支持了u8的功能。ptrCurChar是微软的c1xx.dll中的全局变量的地址,通过它知道当前要解析什么样的代码,解析完之后替换掉它,使得

u8″哈”

交给微软cl.exe解释的时候变成  ”\345\223\210″ 当然下一次再跑到这里的时候,比较是不是解释完我设置的替换串了,是的话换回原始要解释的内容,当然是跳过了u8″哈”这个串的。

即: if(*ptrCurChar == match) *ptrCurChar = replace;

这样处理完了之后,vs2010就完美的支持u8″string”了。不过只能小范围内使用或写一些自己用的工具,对于大的团队而言,还是等微软下一个vs吧,也许那时就真正支持u8″literal string”了。

其实不只是 u8 literal string,这样改编译器,还能实现一些更有意思的东西。

dowload:  hack_c1xx.dll

仅适用于原始md5为D05630986B03CBB28CD4D8E1BDD65831的c1xx.dll。

把原始c1xx.dll改名为c1xx_.dll,把hack_c1xx.dll改名为c1xx.dll

标签:

Test unsigned drivers in windows vista/7 x64

九 23rd, 2010

How to Disable Signature Enforcement during Development

During the early stages of development, developers can disable enforcement in Windows so that driver signing is not necessary. The following options are available for developers to disable kernel mode code signing enforcement temporarily so that Windows Vista will load an unsigned driver.

  • Attaching a kernel debugger. Attaching an active kernel debugger to the target computer disables the enforcement of kernel mode signatures in Windows Vista and allows the driver to load.
  • Using the F8 option. An F8 Advanced Boot Option introduced with Windows Vista—“Disable Driver Signature Enforcement”—is available to disable the kernel-signing enforcement only for the current boot session. This setting does not persist across boot sessions.
  • Setting the boot configuration. A boot configuration setting is available in the Windows Vista Beta2 release that disables the enforcement of kernel mode signatures to be persisted across boot sessions.

bcdedit /copy {current} /d “test_driver”
set GUID={guid-returned-by-previous-command}
bcdedit /set %GUID% loadoptions DDISABLE_INTEGRITY_CHECKS
bcdedit /set %GUID% testsigning on
bcdedit /set %GUID% nointegritychecks ON

标签:

rebuild debian kernel.

九 15th, 2010

apt-get install linux-source-2.6  libncurses5-dev

tar -xjf  /usr/src-linux-source-2.6.32.tar.bz2

cd linux-source-2.6.32

make menuconfig

make KDEB_PKGVERSION=my1.0 deb-pkg

 … to be continue…

标签:

在Debian Linux下编译第一个objc程序

八 12th, 2010

 

首先,我们要安装相应的程序:

apt-get install gcc gobjc gcc g++ gnustep libgnustep-gui-dev

然后编写一个hello.m文件:

连hello.m都是抄来的,哈哈,程序如下:

#import <Foundation/Foundation.h>

@interface HelloWorld : NSObject

- (void) hello;

@end

@implementation HelloWorld

- (void) hello {

NSLog(@”hello world!”);

}

@end

int main(void) {

HelloWorld *hw = [[HelloWorld alloc] init];

[hw hello];

[hw release];

}

然后就是编译了:

编译成.o文件:

gcc -fconstant-string-class=NSConstantString -I /usr/include/GNUstep/ -c hello.m

链接:

gcc hello.o -o hello -lgnustep-base

一些方便的设置:

在bashrc中添加一条:

alias objcc=’gcc -fconstant-string-class=NSConstantString -I /usr/include/GNUstep/ -lgnustep-base’

以上命令就简化啦:

objcc –o hello hello.m

运行:

$ ./hello

2010-08-12 01:03:23.930 hello[1642] hello world!

标签:

virtualbox port forwarding

七 31st, 2010

copied from the manual….

As the virtual machine is connected to a private network internal to VirtualBox and invisible to the host, network services on the guest are not accessible to the host machine or to other computers on the same network. However, like a physical router, VirtualBox can make selected services available to the world outside the guest through port forwarding. This means that VirtualBox listens to certain ports on the host and resends all packets which arrive there to the guest, on the same or a different port.

To an application on the host or other physical (or virtual) machines on the network, it looks as though the service being proxied is actually running on the host. This also means that you cannot run the same service on the same ports on the host. However, you still gain the advantages of running the service in a virtual machine — for example, services on the host machine or on other virtual machines cannot be compromised or crashed by a vulnerability or a bug in the service, and the service can run in a different operating system than the host system.

You can set up a guest service which you wish to proxy using the command line tool VBoxManage; for details, please refer to the section called “VBoxManage modifyvm”.

You will need to know which ports on the guest the service uses and to decide which ports to use on the host (often but not always you will want to use the same ports on the guest and on the host). You can use any ports on the host which are not already in use by a service. For example, to set up incoming NAT connections to an ssh server in the guest, use the following command:

VBoxManage modifyvm "VM name" --natpf1 "guestssh,tcp,,2222,,22"

With the above example, all TCP traffic arriving on port 2222 on any host interface will be forwarded to port 22 in the guest. The protocol name tcp is a mandatory attribute defining which protocol should be used for forwarding (udp could also be used). The name guestssh is purely descriptive and will be auto-generated if omitted. The number after --natpf denotes the network card, like in other parts of VBoxManage.

To remove this forwarding rule again, use the following command:

VBoxManage modifyvm "VM name" --natpf1 delete "guestssh"

If for some reason the guest uses a static assigned IP address not leased from the built-in DHCP server, it is required to specify the guest IP when registering the forwarding rule:

VBoxManage modifyvm "VM name" --natpf1 "guestssh,tcp,,2222,10.0.2.19,22"

This example is identical to the previous one, except that the NAT engine is being told that the guest can be found at the 10.0.2.19 address.

To forward all incoming traffic from a specific host interface to the guest, specify the IP of that host interface like this:

VBoxManage modifyvm "VM name" --natpf1 "guestssh,tcp,127.0.0.1,2222,,22"

This forwards all TCP traffic arriving on the localhost interface (127.0.0.1) via port 2222 to port 22 in the guest.

It is not possible to configure incoming NAT connections while the VM is running. However, you can change the settings for a VM which is currently saved (or powered off at a snapshot).

标签:

debian linux 配置ipsec l2tp PSK

五 9th, 2010

PSK=windows中说的预共享密钥

折腾了一天多,总结一下。一个字:日!

pptp的配置比较简单,三两个就折腾出来了。l2tp配置文章较少,大都说得很轻松的样子。实际上如果环境顺利,也不需要折腾这么久,只是。。。。。

先说下总结出来的步骤:(实验环境debian 192.168.163.133  xp 192.168.1.200 都在vm里)

编辑 /etc/sysctl.conf 启用 ipv4 forward.  
sysctl –p 应用

安装组件
apt-get install pptpd l2tpd openswan ipsec-tools

修改 /etc/ipsec.secrets,设置PSK。
192.168.163.133  %any: PSK “12345678″

修改 ipsec.conf

Copy /etc/ipsec.d/examples/l2tp-psk.conf 的两个conn段配置

修改:

gateway
….
rightprotoport=17/%any

修改/etc/xl2tp/xl2tp.conf

[global]
port = 1701
[lns default]
ip range = 192.168.254.20-192.168.254.255
local ip = 192.168.254.2
require chap = yes
refuse pap = yes
require authentication = yes
name = pandora
pppoptfile = /etc/ppp/options.l2tpd.lns
flow bit = yes

创建 /etc/ppp/options.l2tpd.lns

ms-dns 8.8.8.8
ms-dns 208.67.222.222

重启服务。以上实际上就是顺利情况下要做的事情了。

但我折腾了一天多!因为….

rightprotoport=17/%any这一句,默认是rightprotoport=17/0

此时会出错,啥也连不上,改成%any,折腾了好久想到要改这里,改成%any,还是不行,改成17/1701,好,终于行了。

换到正式环境,还是不行。最终tcpdump发现,写成17/1701,则只有公网IP才能连上服务器!

准确的说,也不是公网IP,而是服务器的包要发回到源IP的1701端口,发得通才能连上。所以实验环境的两相同子网虚拟机可连。

正式环境里用公网IP不用家里路由器拨号可连。但在内网就不可连。所以写成17/1701是太不好用了。但写成%any或0都不可以。

实验环境的debian和正式环境的ubuntu都验证了这一现象。

改了配置查了错误数据,是这样的提示:

control_finish: Peer requested tunnel 56 twice, ignoring second one.

搜一下这个错误,网上有很多难兄难弟,但基本都没个结论。比如这位仁兄:http://bbs.chinaunix.net/viewthread.php?action=printable&tid=1422551

为什么?不得不怀疑是BUG!apt-get remove  openswan。下载最终版编译安装。17/%any好了。也就是说:

debian和unbuntu的openswan 2.6.23+dfsg-1 有严重bug, rightprotoport=17/0和rightprotoport=17/%any不能用!

 绝大多数时间就耗在斗争这个问题了。而且换成最新版的openswan 2.6.25之后,rightprotoport=17/0还是不能工作!只是17/%any可以了。

中间还出现过别的问题 ,在配置 /etc/ppp/options.l2tpd.lns 时,win7突然连不上服务器了,XP可以。怎么配来配去甚至配回去都不行。无耐重启WIN7,还是不行。再重启了服务,终于行了。看来这个鬼服务一点鲁棒性也没有。

不过,即使是最终配到现在,也还是有一个问题没有解决。那就是,同一个内网里,只有一个设备可以连接。WIN7上去了,XP就上不去了,反之同样。还好我的目的是给手机用,此问题暂时忽略。不过还是很不爽,这意味着在公司,我不能把这个设置告诉别人了,因为大家在同一内网,别人一连L2tp,我就连不了了。只能让别人连pptp。如果有哪位知晓,请回复告之。

todo:view this.

标签:

用vs2010自带工具制作文件证书

五 8th, 2010

以便给自己的程序签名,呵呵。

当然,这样签 发的程序在别人那是不被信任的。除非把自己的根证书给别人安装。

用命令行,使用如下命令:

makecert  -pe -ss swigger -n “CN=swigger.net” -sv swigger_root.pvk -r swigger_root.cer

这里会弹出框要求密码,输入密码 root_pwd 或其它密码。共输入3次,前两次设置,后一次验证。

makecert -is swigger -n “CN=swigger file sign” -$ commercial -ic swigger_root.cer -sv fs.pvk fs.cer

这里继续弹出要密码,设置为 pwd2 或其它密码。共输入三次,两次设置,一次确认。还会弹出第四次要密码,要输入上一步设置的密码 root_pwd (或其它值)。

cert2spc fs.cer fs.spc

以下两条命令的pwd2是第二步设置的密码,如果不是pwd2,要换成其它值。

pvk2pfx -pvk fs.pvk -pi pwd2 -spc fs.spc -pfx fs.pfx -f

signtool sign /t http://timestamp.verisign.com/scripts/timstamp.dll  /v  /f fs.pfx /p pwd2  filename.exe

签名完成后,把swigger_root.cer安装到受信用的根证书,就显示文件正常签名了。

标签:

中国大陆所有IPV4列表

五 7th, 2010

见: http://ipwhois.cnnic.cn/ipstats/detail.php?obj=ipv4&country=CN

这个很重要,先记下。稍候出一份整理好的。

update: http://code.google.com/p/chnroutes/   不用自己操刀了,哈哈。

标签:

移动XP不欢迎的驱动

四 25th, 2010

1. iastor.sys  。这是某些机器上的SATA驱动,没它不行,但这个驱动存在一个BUG,如果没有合适的硬件,加载它就可能会导致系统蓝屏。因此把它集成到WINXP的安装盘,安装系统时,在另一种硬件下,集成的安装盘就不能用了,会蓝屏死机。解决办法:修改iastor.sys,把引发蓝屏的那一条释放内存语句跳过。可能会造成一点点内存泄漏,但这无所谓了。

2. intelppm。intel CPU的驱动。换到amd下时,它会引发蓝屏。解决办法:sc config intelppm start= demand 。 设为手动启动。

此外,遇到一个问题,系统设置的分辨率太高,启动的显示器提示分辩率太高,看不到任何东西。这样也无法修改分辨率。。。解决办法:启动到PE,挂接注册表。删除相关的硬件配置:
\SYSTEM\ControlSet001\Control\Video
\SYSTEM\ControlSet001\Hardware Profiles\000?\System\CurrentControlSet\Control\VIDEO

标签:

为android 生成 native 程序

四 11th, 2010

 

为android生成原生应用程序,不难啊。
初始条件:安装android的ndk,比如目前最新的 android-ndk-r3。(2010-03版)
我的目录结构:
~/android-ndk-r3
~/android-ndk-r3/temp  这个是当前工作目录。

Step1: 写两个文件:
hello.c:

#include <stdio.h>
 
int main()
{
    printf("hello, world\n");
    return 0;
}

start.c

#include <stdlib.h>
extern int main(int argc, char **argv);
 
void _start(int argc, char **argv)
{
    exit (main (argc, argv));
}

Step2: compile
[code]
../build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/arm-eabi-gcc \
-I ../build/platforms/android-3/arch-arm/usr/include/  -c hello.c
../build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/arm-eabi-gcc \
-I ../build/platforms/android-3/arch-arm/usr/include/  -c start.c
[/code]

Step3: link
[code]
../build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/arm-eabi-ld --entry=_start \
--dynamic-linker /system/bin/linker -nostdlib     -rpath /system/lib  \
-L ../build/platforms/android-3/arch-arm/usr/lib/  \
-rpath ../build/platforms/android-3/arch-arm/usr/lib/    \
-lc -o hello hello.o start.o
[/code]

Step4: execute:
[code]
adb push hello /data/hello
adb shell
cd /data
chmod 755 ./hello
./hello
hello, world
[/code]

值得注意的一点是,在/sdcard目录下,程序运行不起来。我一开始还以为是没编好呢。后来扔到/data目录下,才成功跑起来。

标签: