How to use unpublicized APIs in Symbian

1. Why are these APIs unpublicized?

You can usually find the unpublicized APIs in four ways:

  1. APIs are written in SDK document, but marked as “Published Partner” or “Internal”.
  2. APIs are declared in header file with corresponding linkable library, but not documented.
  3. APIs are dumped from linkable library, but nowhere declared.
  4. APIs are exported from dynamic libraries without corresponding linkable library.

* “Linkable library” is a stub library which hold the information required for the linker to link client programs to the correct ordinals to the real dll. In emulator build or Symbian pre-9 toolchain, the linkable library is appeared as .lib file, but in target build of Symbian 9 onwards, it is actually a dummy dynamic library of ELF format with extension .dso.

For the first case, Symbian declared the “Rules for API Usage” as following in SDK document:

It is strongly recommended to only use APIs and methods which are classified as PublishedAll. To ensure that your application will work also in future platform releases, using PublishedAll classified APIs and methods is the safest way.

If APIs and methods with other classifications are used (which is strongly discouraged), your application might stop working in future platform versions without any notification from Symbian about deprecation, removal or modification of internal or published partner classified APIs and methods.

As a software developer, I can understand the essentiality of API classification, the more APIs published in SDK, the more compatibility restriction must be enforced in future release. “Published Partner” is a special case, which means the changes can be made in a managed way by notifying the involving partners. By the way, APIs marked as “Deprecated” should never be used unless no more choices, since they are subject to change or be removed in the future release.

For the latter two cases, as APIs are not classified explicitly, they can be either “Internal” or “Deprecated”. So, use these APIs only when no documented ones are suitable.

The last case is rare and even more dangerous for developer usage. Although in practice, Symbian suggests never breaking the export ordinals of dynamic libraries, the absence of library file implies the possibility of ordinal changes, or even that exports were not frozen. (Please correct my if I’m wrong)

In conclusion, always prefer the “Published All” APIs prior to the unpublicized ones. In case unpublicized APIs are used, never ignore the risk of API changes, thus you should carefully test them on the real phone and all future releases (models).

2. Use the undeclared APIs

I start to talk about the usage of unpublicized APIs from the third case, as assumed that you can easily handle the first two cases. All files mentioned later are of emulator build (WINS/WINSCW) except for explicitly declaration.

From a article “How to dump DLL exports using LIB files” on the famous developer community NewLC.com, you can figure out all the knowledge of dumping exports from library. In practice, when you work on emulator build, I recommend the Perl script written by Mika Raento, this script helps generating header file needed by the APIs. On target build of Symbian 9 onwards, the linkable library file is changed to dummy library (.dso) for GNU toolchain, which rendered the old .lib files useless. As a supplement to the article mentioned above, you can use this command to dump exports from .dso file:

objdump -T euser.dso | c++filt

Note: Since the demangling style differs between VC and GNU C++ compiler, you can not get the type of return value from the dumped exports of .dso file. This is a mechanism restriction.

In most time, the libraries are present both in emulator and target build, and they are consistent with each other on the exports, although the ordinals are different. (“Ekern.exe” is an exception, which exports more APIs in armv5 than in winscw). So you just need to generate the header from emulator build, and use it for both builds without any problem. But you may experience the situation that no corresponding library of target build, especially for the real phone related APIs. In this case, you must rebuild the library manually. I will cover the detailed steps in the next chapter.

3. Dig the hidden APIs

In some extreme cases, we have only the dynamic library. No headers, no linkable libraries, even the worse, no symbol names (because Symbian only supports exporting by ordinal). How could we discover and use these hidden APIs?

For the first half, discovery of the hidden interface need some disassembly skills. Basically two approaches, analysis the exported functions themselves, or analysis other executables / libraries which imported them. I will not cover the deep details, as that might be a long story far away from this topic. Necessary parts may be mentioned as a hint. Now let’s go directly into the second half.

As the excutable only need dynamic library for running (dynamic linking), in theory, we just need the dynamic library itself, from which all the rest can be respawned. Since the functions are exported by ordinal, name is not important technically, you can just name the exports a(), b(), c(), and etc, as ordinal grows. But in practice, we all want the accurate name for calling convenience. So, if possible, digging the function or other ones which imported it is a shortcut, hope that you may luckily find the debugging information or calling log text such as “Call foo() …” or “Enter foo() …”. Another tip, exported symbols were generally sorted when library was first released, thus the proximate neighbor symbols can help narrowing the range for name guess. (the sort rule may differs from compiler to compiler) But according to the export freezing mechanism of Symbian, newly introduced functions to a frozen library always add to the last ordinal, which means they don’t comply with the export sorting. So carefully treat them as an exception. After the symbol names are fixed, although we still need further information about the arguments and returning value in order to reconstruct the interface declaration, let me assume that you can finish it well. (Just another disassembly work with the similar fashion).

Now we have a reconstructed header with interface declarations, it’s time to make a dummy linkable library. To achieve this goal, generally you have 2 choices.

The first one is easier but may take more time. You create a normal Symbian project with “TARGETTYPE” set to “dll” and implement all the interfaces defined by the header reconstructed just now with empty function body. Then make and freeze it, you will get the corresponding linkable library. Be sure to double check the frozen .def file for ordinal consistence with original dynamic library. If any ordinal inconsistent, you should review the function name which may be a bad guess, then correct the function name (or modify the .def to force the ordinal fix, personally discouraged) and rebuild it.

The second choice is much more direct, if you are familiar with the format of .def file. Just manually create the .def file with all the pairs of symbol name and ordinal. Then use the tool “elf2e32” to generate the linkable library from .def file directly:

elf2e32 --targetype=implib --definput=foo.def --dso=foo.dso --linkas=foo{000a0000}[10011237].dll

Note: “elf2e32” is only available in Symbian 9 SDK onwards. So you have to use the first method for Symbian pre-9 SDKs.

You have all the materials ready now, just use these APIs like the ordinary ones, and have fun exploring the underhood of Symbian! (:


Revision History:

2008.3.3 Part I (section 1 and 2) was published.
2008.4.9 Part II (section 3) was published.
2008.4.13 Two parts were merged, and section 2 was modified to add library dumping for .dso file in Symbian 9 onwards.

《How to use unpublicized APIs in Symbian》有19个想法

  1. 您好 Feng,我目前的公司需要您这样的高手来获得一些未公开的API,当然是付费方式,如果您有兴趣可以发邮件给我联系,我在北京。

  2. how can I check the DLL’s exported ordinal with my created ordinal in DEF file? Because the dll’s exported ordinal is not visible. please tell me more detail about it. Thanks a lot.

  3. DLL’s export ordinals are the only things connected to the functions which the DLL has implemented, as there are no symbol names.

    If you care about the these connections, IDA will give you all you need in its “export” view. Then according to this, you should check .def file and correct any unmatched ordinals.

  4. Thank your response so quickly :)

    I still have a problem, even I can get the actural DLL’s exported ordinal through IDA, but it is an ordianl number only, I still can not check the consistence with my defined function name in my .DEF file. Or say we don’t know an DLL’s exported ordinal is maped to what function API in it. Therefor, Is the method you issued in your text above realy work ? P.S. Can I speak Chinese next ?

    Thanks :)

  5. 我目前的一个实际情况是:我有Symbian平台上一个DLL的头文件和对应的LIB文件,但缺少dso文件,导致无法在应用程序中连接此库,想通过您这里介绍的方法来自己实现dso,好像没有什么工具软件可以将LIB文件转换成DSO文件的,如果您知道的话也请赐教,谢谢 :) 我对您的方法还是有点疑问:即使我能从DLL中获得API的序号,但我并不知道这些序号分别对应DLL中的什么API的名字,它们只是一些数字而已,又如何能拿这些没有意义的数字去纠正我在自定义的DEF文件中的序号呢?如果不能纠正的话,那我自己手工生成的dso文件肯定就与实际的DLL不能保证一致了。所以请问您在文章中提出的这个使用未公开函数的方法真的可行吗?谢谢 !

  6. 有DLL和LIB,但缺少DSO的情况,可以采用本文第3节所述的第一种方法,而且简单很多。直接从LIB生成编译所需头文件,再补上相应的空函数实现,编译出一对DSO和DLL来,丢弃其中的DLL,剩下的DSO就是你所需要的文件。为了保险起见,可以再核对编译过程中生成的DEF文件与LIB中所记录的“序号-符号名”对应关系是否一致。

    符号名(或者说函数名)对于Symbian的DLL来说没有任何意义,调用DLL提供的接口就是以“序号”作为唯一标识的,名字只是一个方便识别和使用的标记,你可以用“张三”,或者以“李四”来调用它,都没有什么区别。而LIB文件的作用就是为DLL的导出序号约定一组符号名(函数名),因此你要找的对应关系就在这个LIB里面了。

  7. 再次感谢您的答复 :)

    (1)那么我如何从一个LIB文件中得到“序号-符号名”的对应关系数据以及头文件呢?(尽管本例中我已有头文件但还是比较感兴趣这个问题),有什么工具可以适用吗?是不是通过你文中第二节的方法就可以做到呢?

    (2)如果在没有LIB的情况下,也就是你文中提到的这种情况,我好像还是没有理解你是如何做到的:) 因为总的来说,无论是方法一还是方法二,我理解你的思想都是通过在.DEF文件中建立和修正“序号-符号名”对应关系,而这种关系在没有LIB文件的情况下是没有办法做到的对吗?从而也就生成不了对应的DSO文件,这样导致应用程序无法连接和使用该DLL了。我为什么一直提这个函数名呢?不是为了要在DLL中看到它,因为那是不存在的,而是因为应用程序要通过它来连接.dso,即:
    – My Application: calling DLL’s API(name ordinal)
    – My DSO: name ordinal
    – Thirty Party DLL: ORDINAL
    这里前两步小写的ordinal如果和第三步中大写的ORDINAL不一致的话就会造成调用失败或调错函数,原因就在于第二步的name ordinal关系是手工建立的,而且是在没有依据(无LIB)的情况下建立的。

    罗嗦了这么多,不知道我说明白了没有 :)

    非常感谢您的不吝赐教,希望能得到上面两个问题的解答。

  8. (1)我想你没有打开本文中外链的两个页面看过吧,在那里你可以找到完整的答案。也是因为这个原因,我在本文中省去了这部分介绍。

    (2)还是拿一个简单的例子来说吧。比如你手中只有x.dll这个动态库。

    第一步,通过IDA反汇编分析,你发现它的第一个导出接口完成了“关闭手机”的功能,第二个导出接口的作用是“读取IMEI号”。那么现在你可以创建一个头文件,声明这两个接口,分别命名为“Shutdown()和GetIMEI()”。

    第二步,自己建立一个动态库工程,分别为上述两个函数写一个空的实现,直接返回。然后build、freeze,可以得到三个文件:DLL、DSO、DEF。

    第三步,打开DEF文件,发现其中的“序号-函数名”关系为:“1-GetIMEI、2-Shutdown”,这与我们在第一步中得到的分析结果不符。那么手动调整一下,改为“1-Shutdown、2-GetIMEI”。然后再次build。

    最终得到的这个DSO文件就包含了正确对应关系,你的客户程序使用头文件和它就可以正常的调用DLL中的接口了。

  9. 非常感谢您耐心而又详细的解答。
    其实关键就是第一步:我通过IDA反汇编出来后,怎么知道第一个API以及后续的每一个API是干什么的呢?因为没有Symbol只有Ordinal。如果您这里说的第一步能够达成的话,后面就没问题了。

  10. 既然都已经用IDA反汇编出来了,为什么不知道每一个(序号对应的)API是干什么用的呢?这不就是反汇编的初衷么?

    如果你实际用过IDA做反汇编的话,这个问题就不言自明了。

  11. hi
    i have the same question as junnikokuki say, please do send me a signal if anybody know how to solve this problem!

    thanks very much!

发表评论

电子邮件地址不会被公开。 必填项已用*标注